I am trying to configure a startup script which will startup tomcat, monitor the catalina.out for the string "Server startup", and then run another process. I have been trying various combinations of tail -f with grep and awk, but haven't got anything working yet. The main issue I am having seems to be with forcing the tail to die after grep or awk have matched the string.
I have simplified to the following test case.
test.sh is listed below: #!/bin/sh rm -f child.out ./child.sh > child.out & tail -f child.out | grep -q B child.sh is listed below: #!/bin/sh echo A sleep 20 echo B echo C sleep 40 echo D
The behavior I am seeing is that grep exits after 20 seconds , however the tail will take a further 40 seconds to die. I understand why this is happening - tail will only notice that the pipe is gone when it writes to it which only happens when data gets appended to the file. This is compounded by the fact that tail is to be buffering the data and outputting the B and C characters as a single write (I confirmed this by strace). I have attempted to fix that with solutions I found elsewhere, such as using unbuffer command, but that didn't help.
Anybody got any ideas for how to get this working how I expect it? Or ideas for waiting for successful Tomcat start (thinking about waiting for a TCP port to know it has started, but suspect that will become more complex that what I am trying to do now). I have managed to get it working with awk doing a "killall tail" on match, but I am not happy with that solution. Note I am trying to get this to work on RHEL4.
Something like this?
mkfifo child.fifo tail -f child.out > child.fifo & pid=$! grep -q B child.fifo && kill $pid
#!/bin/sh rm -f child.out ./child.sh > child.out & mkfifo child.fifo tail -f child.out > child.fifo & pid=$! grep -q B child.fifo && kill $pid rm child.fifo
Seems to run in 20 seconds.
$ time ./test2.sh real 0m20.156s user 0m0.033s sys 0m0.058s
This way seems to work too:
#!/bin/sh rm -f child.out ./child.sh > child.out & (tail -f child.out | grep -q B child.out)
And if you're seeing it exit immediately sometimes, try adding a sleep 1, i.e.
#!/bin/sh rm -f child.out ./child.sh > child.out & sleep 1 (tail -f child.out | grep -q B child.out)
time ./test2.sh. — Dec 21, 2010 at 02:25
grep -q B filename, since it doesn't check its STDIN, just file's contents (as expected, though). — Jun 24, 2012 at 03:35