head behaviour

Dag-Erling Smørgrav des at des.no
Sun Jun 6 22:15:39 UTC 2010


Doug Barton <dougb at FreeBSD.org> writes:
> If you have a 2 line file named foo that looks like this:
> one
> two
>
> Then do: cat foo | (cat ; echo 'blah' ; cat)
>
> you get:
> one
> two
> blah
> <prompt>
>
> which seems to indicate to me that unless the first command is a shell
> builtin that the first command is going to receive all of the stdin,
> and the second command none of it.

The second command will receive whatever is left after the first is
done.  Otherwise, read(1) loops wouldn't work.  You chose a poor
example, since cat(1) consumes *everything*.  Try using dd(1) instead,
with varying block sizes and counts:

/usr/src/sys% ls | (dd bs=32 count=1 ; echo "** hello **" ; dd bs=32 count=1)
Makefile
amd64/
arm/
boot/
bsm/
1+0 records in
1+0 records out
32 bytes transferred in 0.000156 secs (204913 bytes/sec)
** hello **
cam/
cddl/
compat/
conf/
contrib1+0 records in
1+0 records out
32 bytes transferred in 0.000134 secs (238822 bytes/sec)

The reason why head(1) doesn't work as expected is that it uses buffered
I/O with a fairly large buffer, so it consumes more than it needs.  The
only way to make it behave as the OP expected is to use unbuffered I/O
and never read more bytes than the number of lines left, since the worst
case is input consisting entirely of empty lines.  We could add an
option to do just that, but the same effect can be achieved more
portably with read(1) loops:

% nhead() { for n in $(jot $1) ; do read line ; print $line ; done }   
% jot 15 | (nhead 5 >/dev/null; nhead 3; echo hi; nhead 3)
6
7
8
hi
9
10
11

DES
-- 
Dag-Erling Smørgrav - des at des.no


More information about the freebsd-hackers mailing list