The Computer Oracle

How to read one line from `tail -f` through a pipeline, and then terminate?

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Realization

--

Chapters
00:00 How To Read One Line From `Tail -F` Through A Pipeline, And Then Terminate?
00:41 Accepted Answer Score 14
01:07 Answer 2 Score 2
01:31 Answer 3 Score 1
01:58 Answer 4 Score 0
02:16 Thank you

--

Full question
https://superuser.com/questions/275827/h...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#bash #unix

#avk47



ACCEPTED ANSWER

Score 14


tail -f foo.log | grep -m 1 bar

if the file foo.log is writen rarily to, you can do:

grep -m 1 bar <( tail -f foo.log )

It should be noted that the tail -f will stay in background until it will get another line to output. If this takes long time it might be problematic. solution in such case is:

grep -m 1 bar <( exec tail -f foo.log ); kill $! 2> /dev/null

kill will kill leftover tail -f process, and we hide errors, because it's possible that the tail will be gone by the time kill will be invoked.




ANSWER 2

Score 2


The <() construct works in bash only. My solution is:

sleep $timeout &
pid=$!
tail -n +0 --pid=$pid -F "$file" | ( grep -q -m 1 "$regexp" && kill -PIPE $pid )
wait $pid

Besides it's working in a POSIX shell, one other advantage is that the waiting period can be limited with a timeout value. Note that the result code of this scriptlet is reversed: 0 means the timeout was reached.




ANSWER 3

Score 1


tail -f waiting for SIGPIPE, which, as already pointed out by depesz, can only be triggered by another write of tail -f to a closed pipe after a successful grep -m 1 match, can be avoided if the tail -f command gets backgrounded and its background pid being sent to the grep subshell, which in turn implements a trap on exit that kills tail -f explicitly.

#(tail -f foo.log & echo ${!} ) |
(tail -f foo.log & echo ${!} && wait ) | 
   (trap 'kill "$tailpid"; trap - EXIT' EXIT; tailpid="$(head -1)"; grep -m 1 bar)



ANSWER 4

Score 0


Building on answer https://superuser.com/a/275962/37154 , I realized that if the tail would start too late, some instance of the indicated string may have gone by already. The solution is to make tail list the whole file.

grep -m 1 bar <( exec tail -n +1 -f foo.log ); kill $!