Monitoring file changes in linux, Looking for a specific line

458 Views Asked by At

Assume a linux system with 4 instances of minicom opened and reading serial data input from 4 devices. Each minicom instance is saving the log into the corresponding text file. Serial data is received triggered by specific phisycal events and each event's data packet consists of a header, a footer, and couple of data lines in between:

[timestamp] header
[timestamp] data
[timestamp] data
...
[timestamp] data
[timestamp] footer

[timestamp] header
[timestamp] data
[timestamp] data
...
[timestamp] data
[timestamp] footer

My goal is to monitor the four log files, and each time a file is modified (by minicom) and as soon as the footer line is seen at the end of the file, run some scripts. I tried to use fswatch and inotifywait fot this.

The problems

The rate in which data lines are received in minicom is approximately 6~7 milliseconds. But I don't want fswatch to print a notification for each line. I just want one notification per packet.

Also the number of log lines (hence the time elapsed from beginning to end of a log packet) vary randomly in each event. So it's not possible to set the latency option in fswatch to a constant value and capture each packet with only one notification.

So I guess the only way is to monitor each line added to the files and check for the footer or header and then notify the scripts. But I don't know how to do that.

Any advice or suggestions?

Edit 1

Maybe using tail -n 1 logfile after each fswatch notification and comparing it with "footer" value?

Edit 2

Ok. I found this command in the fswatch manpage:

fswatch -0 logfile.log | xargs -0 -I {} script.sh

and here is the script.sh:

#!/bin/sh
footer='packet end'
newline=$(tail -n 1 $HOME/slave.log | grep "$footer")
if [ "$newline" != "" ];
then
    echo "found"
fi

It works when the last line is not the footer, but as soon as I run echo "packet end" >> logfile.log the scripts goes into an infinite loop and keeps printing found.

1

There are 1 best solutions below

0
On

I came up with this script using inotifywait:

#!/bin/sh
footer='packet end'
portname='port1'
while inotifywait -qq -e modify $HOME/log/"$portname".log; do
    newline=$(tail -n1 $HOME/log/"$portname".log | grep "$footer")
    if [ "$newline" != "" ]; then
        echo 'packet from port1'
    fi
done

By running 4 of these scripts for each serial input I'm able to capture the packet end line and run other commands.

#!/bin/sh
sh port1.sh &
sh port2.sh &
sh port3.sh &
sh port4.sh &

Although occasionally some packets are missed, but that's not so bad.

If anybody knows a better way of doing this please post your answer.