
Para ser claro com a pergunta do título, entendo porque o primeiro morre. Não entendo por que o último não funciona, apenas para adicionar a | cat
ao corpo do loop.
Também talvez relacionado,
while true; do echo y; done
morre imediatamente quando eu morro ^C
, mas matar
while true; do echo y | cat; done
muitas vezes é preciso acertar ^C
mais de uma vez. Às vezes funciona uma vez, outras vezes funciona 2 ou 3 vezes, aí tem hora que preciso segurar ^C
um pouco para ele morrer.
Ambos os comportamentos acontecem no bash e no zsh, embora aquele ^C
pareça ser mais raro no bash.
Para ambos os comportamentos, isso não se limita a adicionar o pipe ao cat
. | dd
, | tee
, etc. também os causam. Até echo y | true
causa isso. Parece ser a presença de algum tubo no corpo do loop.
Por que a presença de um tubo no corpo do loop altera a resposta do loop aos sinais?
Responder1
Em while true; do echo y; done | true
, como echo
está integrado, você tem um processo de subshell que grava y\n
em um loop em um pipe.
Quando true
retorna, a extremidade de leitura desse canal é fechada, portanto, escrever na extremidade de escrita faz com que a SIGPIPE
seja entregue ao processo de escrita. Aqui, esse é o processo subshell que está executando o loop.
Em while true; do echo y | cat; done | true
, é cat
quem grava no pipe. cat
geralmente não é integrado e, mesmo que fosse, em shells diferentes de zsh e ksh, todos os componentes de pipes sempre são executados em processos filhos.
Então, aqui apenas o processo em execução cat
morre e o processo subshell que executa o loop continua executando mais cat
processos que morrem assim que escrevem y\n
em seu stdout.
Em ksh93/ksh2020, se você fizer isso:
$ builtin cat
$ type cat
cat is a shell builtin
$ set -o pipefail
$ while true; do echo y | cat; done | true; kill -l "$?"
PIPE
Desta vez, cat
está embutido e é executado no mesmo processo que o loop (como cat
é o comando mais à direita na primeira linha do pipeline e o ksh não o executa em um subshell), então o subshell canaliza para true
sair e kill -l
confirma que foi morto por um SIGPIPE.