Why does "tail -f ... | tail" fail to produce any output?

tail -f's tail is actually something unknown in the present, so how should the next tail know it. On the other hand tail -f's head is something already known and could therefor be processed.

Or to put it simpler: tail is relative to the end of the file, but the output stream of tail -f got no EOF (at least not before its termination).

If you find the first tail's pid and kill it, you should then see the output from the second.


Technical answer

When running with a stream as input, tail keeps an n-line buffer that it fills as it reads the stream, but it cannot output those lines until it reaches the end of the stream, i.e. it receives a special EOF code when trying to read from the input stream. The invocation tail -f does not exit, thus it will never close its stream, which makes it impossible to e.g. return the 10 last lines of that stream.


tail shows the last X lines. tail -f does the same, but essentially in an infinite loop: on start-up, show the last X lines of the file, then using some OS magic (like inotify), monitor and show new lines.

To do its job, tail must be able to locate the end of the file. If tail cannot find the file's end, it cannot show the last X lines, because "last" is undefined. So what does tail do in this case? It waits until it does find the end of the file.

Consider this:

$ chatter() { while :; do date; sleep 1; done; }
$ chatter | tail -f

This never appears to make progress, because there is never a definite end of file from chatter.

You get the same behavior if you ask tail to give you the last lines from a file system pipe. Consider:

$ mkfifo test.pipe
$ tail test.pipe

stdbuf to get around the perceived problem was a noble attempt. The key fact though is that I/O buffering isn't the root cause: the lack of a definite end-of-file is. If you check out the tail.c source code, you'll see the file_lines function comment reads:

END_POS is the file offset of EOF (one larger than offset of last byte).

and that's the magic. You need an end-of-file for tail to work in any configuration. head doesn't have that restriction, it just needs a start of file (which it might not have, try head test.pipe). Stream oriented tools like sed and awk need neither a start or end of file: they work on buffers.

Tags:

Pipe

Tail