:> yes | strace tee output | head
[...]
read(0, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = 8192
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = 8192
write(3, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = 8192
read(0, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = 8192
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=5202, si_uid=1000} ---
+++ killed by SIGPIPE +++
De man 2 write :
EPIPE
fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal.
Assim, os processos morrem da direita para a esquerda. head sai sozinho, tee é morto quando tenta gravar no pipeline pela primeira vez depois que head saiu. O mesmo acontece com yes após tee ter morrido.
tee pode gravar no pipeline até que os buffers fiquem cheios. Mas pode escrever tanto quanto gosta de um arquivo. Parece que minha versão de tee escreve o mesmo bloco em stdout e no arquivo.
head tem 8K em seu buffer de leitura (isto é, o kernel). Ele lê tudo isso, mas imprime apenas as primeiras 10 linhas, porque esse é o seu trabalho.