Observei um comportamento estranho no zsh 5.9 no mac. (A seguir está uma simplificação para reproduzir o erro, não tenta fazer sentido). Se eu executar em um terminal
$> function assigner() { OPTIONS=mutated }
$> function main() { typeset OPTIONS; assigner; echo $OPTIONS }
$> main
Isso produz:
mutated
Mas se eu alterar sutilmente a função principal para redirecionar a saída da chamada de função interna...
$> function main() { typeset OPTIONS; assigner | cat; echo $OPTIONS }
Então o resultado está em branco
E minha var OPTIONS não está mais preenchida. O que esta acontecendo aqui?
Um pipe é um mecanismo de comunicação entre processos.
Em um
A | B
pipelineA
eB
executado simultaneamente com a saída padrãoA
conectada à entrada padrão porB
meio de um tubo.Portanto, eles precisam ser executados em processos separados. Na maioria dos shells, ambos são executados em processos filhos; no zsh, como nas implementações originais do ksh, só
A
é executado em um processo filho (embora ifB
seja um comando externo, ele ainda será executado em um processo filho, é claro).Portanto
assigner | cat
, comoassigner
está sendo executado em um processo shell filho, ele está apenas modificando as variáveis desse subshell, não as do processo shell pai. Quando o pipeline termina, as alterações nas variáveis são perdidas.Aqui, se você quiser
assigner
executar no processo pai, mas ainda tiver sua saída canalizadacat
(executando em um processo separado), poderá redirecionarassigner
a saída de para uma substituição de processo em execuçãocat
:Ou execute
cat
como um coprocesso:Os coprocessos têm seu stdin e stdout redirecionados para um canal para que o processo principal possa alimentar dados para eles e obter datas deles, mas você pode cancelar a parte stdout salvando e restaurando o stdout original usando um descritor de arquivo extra.
(consulte Como você usa o comando coproc em vários shells? para obter mais detalhes sobre como usar coprocessos).
Como alternativa, você pode usar a variável
assigner
definida no mesmo subshell onde é executada, disponibilizando novamente o stdout original usando um fd separado: