For the last few months, I’ve been doing some contracting developing automation scripts in bash. It’s been a fun diversion from my job search and leverages my sysadmin background. It has also improved my command of vi and several tricks in bash scripting. I wanted to share one that may be of help to others.
In the scripts that I wrote, it was necessary to kick of a long-running process and then act on entries written to a log file. I created a watcher routine to accomplish this:
01 successfulRun=0 02 keepRunning=1 03 while [ $keepRunning -eq 1 ] && read -t 3600 line; do 04 case "$line" in 05 *completion string* ) 06 echo "Completed successfully. Exiting monitor." 07 successfulRun=1 08 keepRunning=0 09 ;; 10 *error string* ) 11 echo "ERROR entry found in log. Exiting monitor." 12 keepRunning=0 13 ;; 14 * ) 15 echo "Just another line. Monitor continuing." 16 ;; 17 esac 18 done < <(tail --pid=$$ -n0 -F ${logfile})
It’s a general while loop, but there are some useful features. First, in line 3 is “read -t 3600” which allows the loop to break if nothing gets written to the file for an hour (3600 seconds). After the loop, if keepRunning is 1 and successfulRun is 0, I know it timed out.
Lines 5, 10, and 14 allow for cases for any strings encountered. For my uses, I was looking for a success string which meant my script could continue on. Similarly, if an error string is encountered, I exit accordingly. The last one (line 14) is the default case, which probably isn’t needed unless you want to provide feedback of progress.
The last feature is in line 18. The –pid=$$ option allows the tail command to close the logfile when the parent script completes. That allows for a very nice wrap-up no matter what happens. Nice, huh?