Estou tentando canalizar a saída de um comando para o read
builtin do meu shell e recebo um comportamento diferente para zsh
e bash
:
$ bash -c 'echo hello | read test; echo $test'
$ zsh -c 'echo hello | read test; echo $test'
hello
Embora isso não funcione em bash
, o seguinte funciona para ambos:
$ bash -c 'echo hello | while read test; do echo $test; done'
hello
$ zsh -c 'echo hello | while read test; do echo $test; done'
hello
Por que é que? Estou usando read
errado? Acho muito mais legível usá-lo em scripts em comparação com o test="$(echo hello)"
que me obriga a lidar com problemas de citação com muito mais cuidado.
Você está observando os resultados do que não foi padronizado com POSIX.
O POSIX não padroniza como o interpretador executa um pipe.
Com o histórico Bourne Shell, o programa mais à direita em um pipeline nem é filho do shell principal. A razão para fazê-lo desta forma é porque esta implementação é lenta, mas precisa de pouco código - importante se você tiver apenas 64 kB de memória. Como nesta variante, o
read
comando é executado em um subprocesso, atribuir uma variável de shell em um subprocesso não é visível no shell principal.Shells modernos como
ksh
oubosh
(o recente Bourne Shell) criam pipes de uma forma em que todos os processos em um pipe são filhos diretos do shell principal e, se o programa mais à direita for um shell embutido, ele será executado pelo shell principal.Tudo isso é necessário para permitir que o
read
programa modifique uma variável de shell do shell principal. Portanto, apenas nesta variante (que BTW é a variante mais rápida) permite que o shell principal veja os resultados da atribuição da variável.No seu segundo exemplo, todo o
while
loop é executado no mesmo subprocesso e, portanto, permite imprimir a versão modificada da variável shell.Atualmente, há uma solicitação para adicionar suporte ao shell POSIX para obter informações sobre se algum dos comandos do pipeline tem um código de saída diferente de zero. Para conseguir isso, um shell deve ser implementado de forma que todos os programas de um pipeline sejam filhos diretos do shell principal. Isto está próximo do que é necessário para permitir
para fazer o que é esperado, pois falta apenas o requisito de executar a leitura no shell principal.