When true
exits, the read side of the pipe is closed, but yes
continues trying to write to the write side. This condition is called a "broken pipe", and it causes the kernel to send a SIGPIPE
signal to yes
. Since yes
does nothing special about this signal, it will be killed. If it ignored the signal, its write
call would fail with error code EPIPE
. Programs that do that have to be prepared to notice EPIPE
and stop writing, or they will go into an infinite loop.
If you do strace yes | true
1 you can see the kernel preparing for both possibilities:
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17556, si_uid=1000} ---
+++ killed by SIGPIPE +++
strace
is watching events via the debugger API, which first tells it about the system call returning with an error, and then about the signal. From yes
's perspective, though, the signal happens first. (Technically, the signal is delivered after the kernel returns control to user space, but before any more machine instructions are executed, so the write
"wrapper" function in the C library does not get a chance to set errno
and return to the application.)
1 Sadly, strace
is Linux-specific. Most modern Unixes have some command that does something similar, but it often has a different name, it probably doesn't decode syscall arguments as thoroughly, and sometimes it only works for root.
yes | tee >(true) >/dev/null
will do as you expect, btw, astee
continues until all writers are dead, sotrue
exiting won't disrupt it entirely.true
is basically a{return 0;}
program, so I wouldn't expect it to run for long, let alone forever.