1

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.

1 Answers1

1

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"
Philippe
  • 20,025
  • 2
  • 23
  • 32
  • Yes `Philippe`, this coding is more efficient and seems to solve the fact that lines were lost before. Is it because `inotifywait -m` buffers the events occurring on the file ? However, I gave a simplified version of the script, and I need to kill this `inotifywait -m`. And this causes to erase all the variables which were allocated in the while loop. How to preserve them ? – Laurent Mortier Apr 20 '20 at 07:02
  • Thanks again `Philippe`. This solution avoids to kill `inotifywait` since a simple break is enough when the script is triggered to exit. But it generates a new problem. Inside the `while loop`, there is an `ssh other_machine do_something &` triggered by some keyword found in the log, that makes the `while loop` break. Could it be because the `ssh` send a success (or failure) message back to the script which conflicts with the `< <(inotifywait ...)` ?? – Laurent Mortier Apr 20 '20 at 13:51
  • ssh does not seem to have problem. Following parts do have problems, like `==` should be `=`. – Philippe Apr 20 '20 at 18:43
  • Strange. Actually, the `if [ $( echo $action | cut -c1-5 ) == 'CLOSE' ]` (not standard, this is true, I've changed it however), works. The script with ssh commented or not (no other change) has the 2 behaviours described above. I tested this in simulation mode, because I don't want to waste the real communication with the drone which happens every 6h only. – Laurent Mortier Apr 20 '20 at 18:59
  • I've just re-done the test: with ssh, I got `read: Erreur de lecture : 0 : Ressource temporairement non disponible` and exit from the loop. If the script kills it self the inotifywait, I got exactly the same message. Without ssh, it works normally. – Laurent Mortier Apr 20 '20 at 19:11
  • ssh may have problem by itself, but it does not affect overall structure of the script. – Philippe Apr 21 '20 at 07:36
  • In fact the answer is here [https://stackoverflow.com/questions/13800225/shell-script-while-read-line-loop-stops-after-the-first-line]. Thanks for you help, and the progress I made with bash ! – Laurent Mortier Apr 21 '20 at 09:20