The commands are connected with a pipe (I'm talking the system primitive here—obviously, they're connected with a |
). When the read end of the pipe (the stdin
of head
) becomes close
d (== when head
either explicitly (close
) or implicitly (exit) closes it), attempts to write to the write end (stdout
of yes
) will fail.
By default, this is not just a regular errno
failure, but a failure that results in the writing process receiving the SIGPIPE
signal. The default handler action of the SIGPIPE signal is to terminate.
In short—if you write to a broken pipe, the system will send you a SIGPIPE
and by default, a SIGPIPE
will kill you. That is why yes
terminates when head
has ended (and thereby broken the pipe).
If you ignore SIGPIPE
in the parent shell, then the commands will inherit this disposition and a write
to a broken pipe will simply cause an errno
error of EPIPE
. As it appears, yes
stringifies this error an prints it:
$ (trap "" SIGPIPE; yes | head -n 5)
y
y
y
y
yes: standard output: Broken pipe
yes: write error