Exit tail upon string detection

为君一笑 提交于 2019-12-11 03:06:41

问题


I'm writing a barrier to stop to hold the execution of a script until a certain keyword is logged. The script is pretty simple:

tail -F -n0 logfile.log | while read LINE; do
    [[ "$LINE" == *'STOP'* ]] && echo ${LINE} && break;
done

or

tail -F -n0 logfile.log | grep -m1 STOP

Still, despite printing STOP as soon as it is detected, these chunks of code terminate only after the following line is written. I.e:

printf "foo\n" >> logfile.log  # keeps reading
printf "foo\n" >> logfile.log  # keeps reading
printf "STOP\n" >> logfile.log # STOP printed
printf "foo\n" >> logfile.log  # code exits at last

Unfortunately I have no guarantee another line of code will be logged after STOP (not within an interval useful for my purposes).

The workaround found so far is to tail also another file I know for sure gets updated quite frequently, but what is the "clean" solution so that the code will exit right after it logs STOP?


回答1:


In bash, when executing a command of the form

command1 | command2

and command2 dies or terminates, the pipe which receives /dev/stdout from command1 becomes broken. This, however, does not terminate command1 instantly.

So to achieve what you want is to use process substitution and not a pipe

awk '/STOP/{exit}1' < <(tail -f logfile)

When you use awk, you can see the behaviour in a bit more detail:

$ touch logfile
$ tail -f logfile | awk '/STOP/{exit}1;END{print "end"}'

This awk program will check if "STOP" is seen, and if not print the line again. If "STOP" is seen it will print "end"

When you do in another terminal

$ echo "a" >> logfile
$ echo "STOP >> logfile
$ echo "b" >> logfile

You see that awk prints the following output:

a             # result of print
end           # awk test STOP, exits and executes END statement

Furthermore, if you look more closely, you see that awk is at this point already terminated.

ps before sending "STOP":

13625 pts/39   SN     0:00  |        \_ bash
32151 pts/39   SN+    0:00  |            \_ tail -f foo
32152 pts/39   SN+    0:00  |            \_ awk 1;/STOP/{exit}1;END{print "end"}

ps after sending "STOP":

13625 pts/39   SN     0:00  |        \_ bash
32151 pts/39   SN+    0:00  |            \_ tail -f foo

So the awk program terminated, but tail did not crash because it is not yet aware the pipe is broken as it did not attempt to write to it.

When you do the following in the terminal with the pipeline, you see the exit status of tail:

$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
$ 141 0

Which states that awk terminated nicely, but tail terminated with exit code 141 which means SIGPIPE.



来源:https://stackoverflow.com/questions/52813302/exit-tail-upon-string-detection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!