Given a file "foo.txt"
, created from:
$ seq 1 10 > "foo.txt"
I'm trying to read both the first and last line of the file, and I started by redirecting the file to a subshell, so that the list of commands will consume the file in sequence -- each command consumes the input from the point the last command has left it, I suppose:
$ (head -1; tail -1) < "foo.txt"
1
10
However, if I try the same with a temporary file descriptor, the output is not the same:
$ (head -1; tail -1) < <(seq 1 10)
1
Questions:
I'm not sure of what to name <(seq 1 10)
, but what is the difference between this temporary file descriptor and a regular one ("foo.txt"
), that causes the subshell execution to behave differently?
How can I achieve the same behavior of redirecting a "foo.txt"
to the subshell, but without a temporary file -- without actually creating a file.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With