6

Why doesn't yes | head hang?

I thought the system collects all of the result from yes and then pipes it to head, and because yes is an infinite loop, the system hangs. But, it can actually stop and show 10 lines of y.

How does the system manage to stop yes when head is done collecting data?

Adrian Heine
  • 4,051
  • 2
  • 30
  • 43
Antares
  • 213
  • 1
  • 8

2 Answers2

5

When you say yes | head the shell will arrange things such that the output of yes goes to a pipe and the input of head comes from that same pipe. When head reads 10 lines, it closes its STDIN_FILENO, thereby closing its end of the pipe. When yes tries to write to a closed pipe it gets a SIGPIPE whose default action is to kill it.

A simple way to test this is with strace:

$ strace yes | head
y
[...]
y
write(1, "y\ny\ny\ny\ny\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=4069, si_uid=1000} ---
+++ killed by SIGPIPE +++
cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • The `-f` option isn't doing anything useful there. It looks like an attempt to trace both `yes` and `head`, but it doesn't do that because `strace` isn't a special shell builtin that can see a whole pipeline. –  Jan 25 '14 at 18:53
  • @WumpusQ.Wumbley I wasn't aiming at tracing both; `strace -f` is just a reflex I picked up. I removed it, good call :-) – cnicutar Jan 25 '14 at 19:24
4

the system collects all of the result from yes and then pipes it to head

That would be extremely inefficient. When you use a pipe, the operating system creates a buffer for the pipe communication.

send | receive

As long as there's enough space in the buffer the sending process will write in it, and if there's enough data in the buffer, the receiver will process it. If there isn't the waiting process is blocked.

As soon as head finishes, the OS notices that it terminated, it will trigger a signal (SIGPIPE) which will terminate the sending process (unless the process handles it).

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • 2
    The final paragraph is sketchy. The OS does not send the signal 'as soon as head finishes'. Rather, when head finishes, the OS closes the read side of the pipe. When `yes` is rescheduled, it will (eventually) attempt to write into the pipe, at which point the signal is raised. Consider the difference between `yes > /dev/null | true` and `yes | true`. – William Pursell Jan 25 '14 at 13:39