Search code examples
bashtailinotifywait

monitoring and searching a file with inotify, and command line tools


Log files is written line by line by underwater drones on a server. TWhen at surface, the drones speak slowly to the server (say ~200o/s on a phone line which is not stable) and only from time to time (say every ~6h). Depending on the messages, I have to execute commands on the server while the drones are online and when they hang up other commands. Other processes may be looking at the same files with similar tasks.

A lot can be found on this website on somewhat similar problems but the solution I have built on is still unsatisfactory. Presently I'm doing this with bash

while logfile_drone=`inotifywait -e create --format '%f' log_directory`; do

    logfile=log_directory/${logfile_drone}

    while action=`inotifywait -q -t 120 -e modify  -e close --format '%e' ${logfile} ` ; do

        exidCode=$?
        lastLine=$( tail -n2  ${logFile} | head -n1 ) # because with tail -n1 I can got only part of the line. this happens quite often
        match =$( # match set to true if lastLine matches some pattern )

        if [[ $action == 'MODIFY' ]] && $match ; then # do something ; fi

        if [[ $( echo $action | cut -c1-5 ) == 'CLOSE' ]] ; then 
            # do something
            break
        fi  

        if [[ $exitCode -eq 2 ]] ; then break ; fi  

    done

    # do something after the drone has hang up

done # wait for a new call from the same or another drone

The main problems are :

  1. the second inotify misses lines, may be because of the other processes looking at the same file.

  2. the way I catch the time out doesn't seem to work.

  3. I can't monitor 2 drones simultaneously.

Basically the code works more or less but isn't very robust. I wonder if problem 3 can be managed by putting the second while loop in a function which is put in background when called. Finally, I wonder if a higher level language (I'm familiar with php which has a PECL extension for inotify) would not do this much better. However, I imagine that php will not solve problem 3 better than than bash.

Here is the code where I'm facing the problem of abrupt exit from the while loop, implemented according to Philippe's answer, which works fine otherwise:

    while read -r action ; do
        ...
        resume=$( grep -e 'RESUMING MISSION' <<< $lastLine )
        if [ -n "$resume" ] ; then
            ssh user@another_server "/usr/bin/php /path_to_matlab_command/matlabCmd.php --drone=${vehicle}" &
        fi

        if [  $( echo $action | cut -c1-5 ) == 'CLOSE' ] ; then ... ; sigKill=true ; fi
        ...
        if $sigKill ; then break; fi

    done < <(inotifywait -q -m -e modify  -e close_write   --format '%e' ${logFile})

When I comment the line with ssh the script can exit properly with a break triggered by CLOSE, otherwise the while loop finishes abruptly after the ssh command. The ssh is put in background because the matlab code runs for long time.


Solution

  • monitor mode (-m) of inotifywait may serve better here :

    inotifywait -m -q -e create -e modify -e close log_directory |\
    while read -r dir action file; do
        ...
    done
    

    monitor mode (-m) does not buffer, it just print all events to standard output.

    To preserve the variables :

    while read -r dir action file; do
        echo $dir $action $file
    done < <(inotifywait -m -q -e create -e modify -e close log_directory)
    
    echo "End of script"