Shell inotifywait(1) and infinite loop

Hello All,

I wrote a shell script which monitors the FTP log file for new file uploads. Upon a file upload event, the script does some simple parsing of the log file entry and sends email.

Here is the stripped down version of the script:

Code:
#!/bin/sh

inotifywait -q -m -e modify $LOGFILE |
while true;
do
    if tail -n 1 $LOGFILE | grep uploaded > /dev/null 2>&1
    then
        [process log file entry]
        [send mail]
    fi
done

However, instead of sending 1 message, the script sends many, in fact, the script sends dozens of messages for a single file upload event.

For testing purposes I added a loop counter which shows that the same log file entry is picked up by several consecutive cycles of the loop, hence a message is sent for each cycle.

What am I missing? Thanks for any good suggestions...
 
That does not make sense. Shouldn't you use the tail(1) from base system, now providing the -F option for this kind of problem ?

(imagine 2 xterms)
Code:
 $ tail -F log
foo
foo2
foo3
Code:
 $ echo foo > log
$ echo foo2 > log
$ mv log log.old
$ echo foo3 > log

Juha
 
Hello Juha,

Is your point that I should be using tail -F instead of tail -n 1?

I understand that the -F switch will continuously display the new lines in the log file even as the log file is rotated. I'm thinking that in this case the infinite loop is providing that by continuously "asking" for the last line in the file.

Actually, a similar construct is shown in the inotifywait(1) man page.

My problem is that inotifywait(1) seems to find the same line several times. Why?
 
You have inotifywait | while-loop, but the latter makes no use of the former, unless the redacted portions do. If the last line of logfile happens to contain the trigger, the redacted portions will keep executing until a different line is logged.

You are pulling my leg?
Juha

Just in case: tail -Fn0 seems to behave nicely, when you start you don't get the existing old stuff again. The stuff you've presumably already seen.
 
Actually, a similar construct is shown in the inotifywait(1) man page.

In the manpage, there's no while true. What you do with your script is wait *once* for inotify to report a change to the file and then enter an infinite loop always reading the last line. This doesn't make sense at all. Just for the sake of completeness, the original example from the manpage:
Code:
#!/bin/sh
while inotifywait -e modify /var/log/messages; do
  if tail -n1 /var/log/messages | grep httpd; then
    kdialog --msgbox "Apache needs love!"
  fi
done
is subject to a race condition -- if the logfile is written to *again* just before tail is called here, a line will be lost. I think this is a design flaw with the whole idea of inotifywait.

My problem is that inotifywait(1) seems to find the same line several times. Why?

As explained above, it's your infinite loop that "finds" this line over and over again.

I think Juha is correct: don't use inotifywait at all and just use what tail gives you. A good implementation of tail already uses some OS specific API for monitoring the file and polls only as a last resort -- the FreeBSD tail uses kqueue(2). inotify is btw the corresponding Linux API and I would expect a Linux tail to use that instead.
 
Back
Top