Como é que `embora seja verdade; faça eco y; feito | true` morre por conta própria, mas `enquanto verdadeiro; faça eco y | gato; feito | verdadeiro` não?

Como é que `embora seja verdade; faça eco y; feito | true` morre por conta própria, mas `enquanto verdadeiro; faça eco y | gato; feito | verdadeiro` não?

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 | catao 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 ^Cmais de uma vez. Às vezes funciona uma vez, outras vezes funciona 2 ou 3 vezes, aí tem hora que preciso segurar ^Cum pouco para ele morrer.

Ambos os comportamentos acontecem no bash e no zsh, embora aquele ^Cpareç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 | truecausa 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 echoestá integrado, você tem um processo de subshell que grava y\nem um loop em um pipe.

Quando trueretorna, a extremidade de leitura desse canal é fechada, portanto, escrever na extremidade de escrita faz com que a SIGPIPEseja entregue ao processo de escrita. Aqui, esse é o processo subshell que está executando o loop.

Em while true; do echo y | cat; done | true, é catquem grava no pipe. catgeralmente 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 catmorre e o processo subshell que executa o loop continua executando mais catprocessos que morrem assim que escrevem y\nem 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, catestá 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 truesair e kill -lconfirma que foi morto por um SIGPIPE.

informação relacionada