Estou no Bash, no Linux Mint. Se eu executar
{ echo 1 || >&2 echo "[ $? ]" ; } | echo
uma linha vazia é impressa. Observe que o Bash interpreta echo
como um built-in. Mas se eu executar
{ /bin/echo 1 || >&2 echo "[ $? ]" ; } | /bin/echo
ele produz
[ 141 ]
Por man bash
sabermos que 141 significa que recebeu o sinal 13, e por man 7 signal
isso significa que houve um sinal SIGPIPE gerado. Em man 7 pipe
lemos que
[i]se todos os descritores de arquivo referentes à extremidade de leitura de um pipe tiverem sido fechados, então a
write(2)
fará com que um sinal SIGPIPE seja gerado para o processo de chamada.
Então concluo que no segundo caso "todos os descritores de arquivo que se referem ao fim de leitura de um pipe foram fechados", seja lá o que isso deva significar para o /bin/echo
. Mas por que a saída é diferente no caso do Bash echo
?
Em
{ echo 1 || >&2 echo "[ $? ]" ; }
eecho
precisam ser executados simultaneamente, ou seja, em processos separados.O
echo 1 || >&2 echo "[ $? ]"
código está sendo avaliado e executado por um processo de shell filho.Como
echo
é integrado, quando ele faz issowrite(1, "1\n", 2)
enquanto o fd 1 está aberto em um pipe quebrado, é o processo do shell que é morto por um SIGPIPE, então ele não pode continuar com a>&2 echo...
parte, pois ela está morta.Se você alterá-lo para:
(também adicionando um
sleep 1
para garantir que o pipe já esteja quebrado no momento doecho 1
), então, como SIGPIPE é ignorado no subshell à esquerda do pipe, owrite()
retorna com umEPIPE
erro, queecho
relata e informa um1
status de saída.Em
O subshell em execução
/bin/echo 1 || >&2 echo "[ $? ]"
bifurca um processo filho no qual ele executaecho
(e então espera por seu término), e esse é o processo que faz owrite(1, "1\n", 2)
e é morto. Então a espera retorna com uma indicação de que o processo que foi executado/bin/echo
foi morto com um SIGPIPE (que resulta em$?
ser 141) e o subshell executa>&2 echo...
.