I am trying to implement a script that wait for a specific message in a log file. Once the message is logged then I want to continue the script.
Here's what I am trying out with tail -f
and grep -q
:
# tail -f logfile | grep -q 'Message to continue'
The grep
never quit and so it waits forever even if 'Message to continue' is logged in the file.
When I run this without -f
it seems to work fine.
After some experimentation, I believe the problem is in the way that
bash
waits for all the processes in a pipeline to quit, in some shape or form.With a plain file 'qqq' of some 360 lines of C source (a variety of program concatenated several times over), and using 'grep -q return', then I observe:
tail -n 300 qqq | grep -q return
does exit almost at once.tail -n 300 -f qqq | grep -q return
does not exit.tail -n 300 -f qqq | strace -o grep.strace -q return
does not exit until interrupted. Thegrep.strace
file ends with:This is one leads me to think that
grep
has exited before the interrupt killstail
; if it was waiting for something, there would be an indication that it received a signal.A simple program that simulates what the shell does, but without the waiting, indicates that things terminate.
With a fixed size file,
tail -f
isn't going to exit - so the shell (bash
) seems to hang around.tail -n 300 -f qqq | grep -q return
hung around, but when I used another terminal to add another 300 lines to the fileqqq
, the command exited. I interpret this as happening becausegrep
had exited, so whentail
wrote the new data to the pipe, it got a SIGPIPE and exited, andbash
therefore recognized that all the processes in the pipeline were dead.I observed the same behaviour with both
ksh
andbash
. This suggests it is not a bug but some expected behaviour. Testing on Linux (RHEL 5) on an x86_64 machine.Admittedly, it exits when the next line is read, not immediately on the matched one.
I thought I'd post this as an answer since it explains why the command exits after a second write to the file:
That's because
tail
with the-f
(follow) option doesn't quit, and continues to provide output togrep
. Waiting for lines in a log file would probably be easier with perl/python.Launch
tail -f
with the Python subprocess module. Read output fromtail
in a loop until you see the lines you want then exit the Python script. Put this solution inside your shell script.The Python script will block the shell script until the desired lines are seen.
I was searching for the answer to this for my own project. Trying to test when exactly the passed through GPU becomes active on a VMware ESXi VM. Multiple variations of the same question are everywhere. This one is pretty recent. I figured out a way to fool it, and if you can live with your interesting line repeated in the log then:
tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel >>/var/log/ vmkernel.log
This tails the log, one line at a time, grep checks each line for first occurrence, and appends it to the log then tail quits immediately.
If you like VMware passthough hacking, read more here: http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer
tail -f
will read a file and display lines later added, it will not terminate (unless a signal likeSIGTERM
is sent).grep
is not the blocking part here,tail -f
is.grep
will read from the pipe until it is closed, but it never is becausetail -f
does not quit and keep the pipe open.A solution to your problem would probably be (not tested and very likely to perform badly):