It's just a buffering issue. Try:
cat foo.txt | ( head -1; tail -1)
and you will (probably) see the same thing (head consumes the entire input). Probably what is happening is that head is behaving differently with a regular file than with a pipe, and the process substitution (which is the name for the <(cmd)
syntax) is creating a pipe. (In Linux, the head
from Gnu coreutils does an lseek
to try to reposition at the final newline that it outputs, but the lseek
fails on a pipe.)
Also try:
(head -1; tail -1) < <(cat /usr/share/dict/words)
Here, head
only consumes the first page of input, and tail sees the final line of the data.
The behavior you are seeing is not well defined, since there is no standard that dictates how much of the data head is allowed to consume. If you replace head
with sh -c 'read line; echo "$line"'
, then you will get the desired behavior in all cases. (Or write your own tool to provide the behavior of head
that you want -- printing a fixed number of lines while not consuming any more than that.)