De acordo com a documentação, o bash aguarda até que todos os comandos em um pipeline concluam a execução antes de continuar
O shell aguarda a conclusão de todos os comandos no pipeline antes de retornar um valor.
Então, por que o comando yes | true
termina imediatamente? O yes
loop não deve para sempre e faz com que o pipeline nunca retorne?
E uma subquestão: de acordo com a especificação POSIX , os pipelines do shell podem optar por retornar após o término do último comando ou aguardar até que todos os comandos sejam concluídos. As conchas comuns têm um comportamento diferente nesse sentido? Existe alguma concha onde yes | true
se repita para sempre?
yes | tee >(true) >/dev/null
fará o que você espera, btw, comotee
continua até que todos os escritores estejam mortos, portanto,true
sair não irá atrapalhá-lo completamente.true
é basicamente um{return 0;}
programa, então eu não esperaria que fosse executado por muito tempo, muito menos para sempre.Respostas:
Quando
true
sai, o lado de leitura do pipe é fechado, masyes
continua tentando gravar no lado de gravação. Essa condição é chamada de "tubo quebrado" e faz com que o kernel envie umSIGPIPE
sinal parayes
. Comoyes
não faz nada de especial nesse sinal, ele será morto. Se ignorasse o sinal, suawrite
chamada falharia com o código de erroEPIPE
. Os programas que fazem isso precisam estar preparados para perceberEPIPE
e parar de escrever, ou entrarão em um loop infinito.Se você fizer
strace yes | true
1, poderá ver o kernel se preparando para as duas possibilidades:strace
está assistindo a eventos por meio da API do depurador, que primeiro fala sobre a chamada do sistema retornando com um erro e depois sobre o sinal. Dayes
perspectiva de, porém, o sinal acontece primeiro. (Tecnicamente, o sinal é entregue depois que o kernel retorna o controle ao espaço do usuário, mas antes que mais instruções da máquina sejam executadas, para que awrite
função "wrapper" na biblioteca C não tenha a chance de definirerrno
e retornar ao aplicativo.)1 Infelizmente,
strace
é específico do Linux. A maioria dos Unixes modernos possui algum comando que faz algo semelhante, mas geralmente tem um nome diferente, provavelmente não decodifica os argumentos do syscall tão completamente e, às vezes, funciona apenas como root.fonte
yes
está conectado ao pipe.yes
obtenção do SIGPIPE, pois o FD para o qual está gravando não está conectado a um pipe.yes >/dev/null
está repetindo para sempre. Ele não demonstra nada sobre pipelines que também não são verdadeiros para comandos simples (como o comportamento de espera pela terminação que Tom ressalta também se aplica a comandos simples).write()
(a função libc) não retorna (transfere o controle para o PC que está seguindo) até depois o manipulador de sinais foi executado, mas, como o manipulador de sinais termina o programa, o controle nunca é transferido e, portanto,write()
nunca retorna. Sim, isso é implementado no kernel com oxxx_write()
retorno de algumas funções-EPIPE
, mas estamos depurando um programa de espaço do usuário e não estamos interessados nisso.Improvável, já que o
yes
comando está usando o pipe e falhará quando o pipe estiver quebrado.sleep
por outro lado, não usa o cachimbo, então:será executado por 100000000 segundos, pelo menos.
fonte
true
está. Isso se aplica a versões recentes doBourne Shell
,ksh93
,zsh
. Se você pressionar^Z
quando um comando estiver em execução, isso suspenderá o sono e o shell nunca poderá se recuperar sem ajuda externa.sbrk()
. A versão portátil e mantida é nas ferramentas Schily agrupar e @Charles Duffy já descobriu um local para obter informações ;-)bsh
(Berthold Shell do VBERTOS, uma versão aprimorada de memória virtual do UNOS - o primeiro clone do UNIX). O Bsh obteve muitos recursos do csh em 1984 e 1985, mas o mecanismo de alias do UNOS já era superior ao do csh em 1980. Outros novos recursos do Bourne Shell são do POSIX, para permitir que ele se aproxime da conformidade com o POSIX.