Quando true
sai, o lado de leitura do canal é fechado, mas yes
continua tentando gravar no lado da gravação. Essa condição é chamada de "pipe corrompido" e faz com que o kernel envie um sinal SIGPIPE
para yes
. Como yes
não faz nada especial sobre este sinal, ele será eliminado. Se ele ignorasse o sinal, sua chamada write
falharia com o código de erro EPIPE
. Programas que fazem isso precisam estar preparados para notar EPIPE
e parar de escrever, ou eles entrarão em um loop infinito.
Se você usar strace yes | true
1 , poderá ver o kernel se preparando para as duas possibilidades:
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
está assistindo eventos por meio da API do depurador, que primeiro informa sobre a chamada do sistema que retorna com um erro e, em seguida, sobre o sinal. Do ponto de vista de yes
, porém, o sinal acontece primeiro. (Tecnicamente, o sinal é entregue depois que o kernel retorna o controle para o espaço do usuário, mas antes que mais instruções da máquina sejam executadas, a função write
"wrapper" na biblioteca C não tem a chance de definir errno
e retornar para a aplicação.)
1 Infelizmente, strace
é específico do Linux. A maioria dos Unixes modernos tem o comando some que faz algo semelhante, mas geralmente tem um nome diferente, provavelmente não decodifica argumentos syscall tão detalhadamente, e às vezes funciona apenas para root.