I want to watch a file until a bit of text appears
I found this answer: `tail -f` until text is seen
but when I tried it on ubuntu, it doesn't exit:
$ echo one > test.txt
$ echo two >> test.txt
$ echo three >> test.txt
$ echo four >> test.txt
$ cat test.txt | sed '/w/ q'
one
two
$
works as expected. however when I try to tail the file
$ tail -f test.txt | sed '/w/ q'
one
two
it never exits. tail does not stop even though the pipe is broken.
Does anybody know how to make tail
exit when sed
exits?
Best Answer
It's the same things as in:
In:
Your shell happens to wait until
cmd1
terminates even aftercmd2
has already terminated. That's not the case of all shells. Some like the Bourne or Korn shell don't for instance.When
cmd2
dies, the pipe oncmd1
's stdout becomes broken, but that doesn't terminatecmd1
instantly.cmd1
will terminate the next time it tries to write to that pipe. It will then receive a SIGPIPE whose default action is to terminate the process.With
cmd1
==tail -f file
andcmd2
==sed /w/q
,tail -f
will read the last 10 lines of the file and write them to stdout (the pipe), typically in one chunk unless the lines are really big and sit there waiting for more text to be appended tofile
.sed
, which runs concurrently, will wait for input on its stdin, read it, process it line by line and quit if there's a line that containsw
.As soon (or possibly with a one-line delay with some
sed
implementation) as it finds that line, it exits, but at that time,tail
has already written to the pipe all it had to WRITE, so it won't receive a SIGPIPE unless some additional text is added later on to the file (at which point it will do the fatalwrite()
).If you wanted
cmd1
to terminate as soon ascmd2
terminates, you'd need something to kill it oncecmd2
terminates. Like with:Or with
bash
:2020 Edit
As noted by @user414777, since version 8.28, the GNU implementation of
tail
, in follow modes, now not only polls for new data in the file(s) it monitors but also checks whether its stdout becomes a broken pipe and exits straight away then (or within one second if inotify is not used), making those work arounds above unnecessary.However note that only GNU
tail
does this kind of processing, not any other implementation oftail
(AFAIK), and not any other utility (even the GNU implementations).So, while:
Will exit after one line,
for instance will not necessarily as
tr
will not monitor whether its stdout becomes a broken pipe, and so will only die if it writes something there after the pipe has broken as usual (and it's only at that point that GNUtail -f
will exit).