Using tail combined with other standard tools in Grouping Commands can make some powerful constructions. For example, to get the first and last line of a file:$ seq 10 > file$ { head -n1; tail -n1; } <file110When feeding file contents from a pipe to group commands, tail fails to produce output, because a pipe is un-lseekable:$ seq 10 | { head -n1; tail -n1; }1Now, when the content is big enough, tail works:$ seq 10000 | { head -n1; tail -n1; }110000That's because after the first lseek failure, tail know it's not a lseekable file descriptor and because the contents of the pipe haven't been read all yet, it starts to read the content till the end.As the user point of view, I expect that the behavior should be consistent regardless of input content size. I've looked through POSIX tail, lseek documentation and didn't find out any description.Is this behavior specified by POSIX? If not, how can I make the result to be always consistent?I have tested with GNU tail and FreeBSD tail, both have the same behavior.
Is this tail behavior in Grouping Commands specified by POSIX?
pipe;tail;posix
Note that the problem is not with tail but with head here which reads from the pipe more than the first line it is meant to output (so there's nothing left for tail to read).And yes, it's POSIX conformant.head is required to leave the cursor within stdin just after the last line it has output when the  input is seekable, but not otherwise.http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html:When a standard utility reads a seekable input file and terminates without an error before it reaches end-of-file, the utility shall ensure that             the file offset in the open file description is properly positioned just past the last byte processed by the utility. For files that are not             seekable, the state of the file offset in the open file description for that file is unspecified.For head to be able to do that for a non-seekable file would mean it would have to read one byte at a time which would be terribly inefficient. That's what the read or line utility do or GNU sed with the -u option.So you can replace head -n 20 with gsed -u 20q if you want that behaviour.Though here, you'd rather want:sed -e 1b -e '$b' -e dinstead. Here, only one tool invocation, so no problem with an internal buffer that can't be shared between two tool invocations.See the related discussion about buffering at Why is using a shell loop to process text considered bad practice?.Note that tail must output the tail of the stream on stdin. While, as an optimisation and for seekable files, implementations may seek to the end of the file to get the trailing data from there, it is not allowed to seek back to a point that would be before the initial position at the time tail was invoked (Busybox tail used to have that bug).So for instance in:{ cat; tail -n 1; } < fileEven though tail could seek back to the last line of file, it does not. Its stdin is an empty stream as cat left the cursor at the end of the file; it's not allowed to reclaim data from that stream by seeking further backward in the file.