You should kill it explicitly
seq 1 10 > file
tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; } | tee output
pkill -PIPE -xg0 tail
means
send a SIGPIPE
signal to the process named exactly tail
from the same process group as ourselves.
This assumes that there is no other tail
running in the same process group. If the command is run from an interactive terminal (from a shell with job control), it should be safe, as each pipeline is then run in its own process group (aka job). In a shell without job control (e.g. in a script), we could wrap the pipeline in a separate shell where the job control is explicitly turned on:
sh -mc 'tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; }' | tee output
But GNU tail kills itself
If you're using a Linux machine with bash and coreutils, you will notice that everything falls into place, and there's no need of any kill
whatsoever; tail
will simply terminate by itself:
debian$ tail -f file | sed /2/q
1
2
debian$ # WOW!
That's because the tail
from GNU coreutils is using a smart trick to determine if its stdout is still writable: it's polling it for a "ready for reading" condition, which on the writing end of a pipe will only happen in case of error, as when its other end has been closed. If that's the case, then tail
just kills itself with a SIGPIPE
signal. Quoting from its source code:
FD_SET (STDOUT_FILENO, &rfd);
/* readable event on STDOUT is equivalent to POLLERR,
and implies an error condition on output like broken pipe. */
if (select (STDOUT_FILENO + 1, &rfd, NULL, NULL, &delay) == 1)
die_pipe ();
[In fact, other systems may POLLHUP
or POLLHUP|POLLIN
instead of POLLERR
, but this doesn't matter in practice]
GNU tail only does this on pipes, not on sockets or ttys (which means that that doesn't work with ksh93, which is using kneecapped unix-domain sockets to implement its "pipes").
Also (AFAIK) only GNU tail
does this at all, and only since version 8.28; even on Linux, busybox tail
does not.
That means that using tail -f | quit_at_some_point
(from many answers here) is still very much hit-and-miss, and may actually never terminate.
tail -f
hangs around only until its sleep interval ends. So, in order to make it terminate faster, invoke it with--sleep-interval=N
, e.g.tail -f -s 0.01 logfile | sed '/special string/q' | tee output.txt
.special string
, matching anything in the log file when interpreted as a regular expression?