Sim, bash
como em ksh
(de onde o recurso vem), os processos dentro da substituição do processo não são esperados (antes de executar o próximo comando no script).
para <(...)
um, geralmente é bom como em:
cmd1 <(cmd2)
o shell estará aguardando cmd1
e cmd1
normalmente estará aguardando em cmd2
virtude da leitura até o final do arquivo no tubo substituído, e esse fim do arquivo normalmente acontece quando cmd2
morre. Essa é a mesma razão várias conchas (não bash
) não se incomode à espera de cmd2
no cmd2 | cmd1
.
Pois cmd1 >(cmd2)
, no entanto, esse geralmente não é o caso, pois é mais o cmd2
que normalmente espera por cmd1
isso, e geralmente sai depois.
Isso está fixo no zsh
que aguarda por cmd2
lá (mas não se você o escrever como cmd1 > >(cmd2)
e cmd1
não estiver embutido, use {cmd1} > >(cmd2)
como documentado ).
ksh
não espera por padrão, mas permite que você espere por ele com o wait
built-in (também disponibiliza o pid $!
, embora isso não ajude se você o fizer cmd1 >(cmd2) >(cmd3)
)
rc
(com a cmd1 >{cmd2}
sintaxe), o mesmo que com a ksh
exceção de que você pode obter os pids de todos os processos em segundo plano $apids
.
es
(também com cmd1 >{cmd2}
) aguarda o cmd2
like in zsh
e também aguarda redirecionamentos cmd2
no <{cmd2}
processo.
bash
torna disponível o pid cmd2
(ou mais exatamente do subshell, como ele é executado cmd2
em um processo filho desse subshell, mesmo que seja o último comando) $!
, mas não deixa você esperar por ele.
Se você precisar usar bash
, poderá solucionar o problema usando um comando que aguardará os dois comandos com:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Isso faz os dois cmd1
e cmd2
tem seu fd 3 aberto em um cano. cat
aguardará o final do arquivo na outra extremidade e, portanto, normalmente somente sairá quando ambos cmd1
e cmd2
estiverem mortos. E o shell aguardará esse cat
comando. Você pode ver isso como uma rede para capturar o término de todos os processos em segundo plano (você pode usá-lo para outras coisas iniciadas em segundo plano, como &
coprocs ou mesmo comandos que são em segundo plano, desde que não fechem todos os descritores de arquivos, como os daemons normalmente fazem )
Observe que, graças ao processo desperdiçado do subshell mencionado acima, ele funciona mesmo se cmd2
fechar o fd 3 (os comandos geralmente não fazem isso, mas alguns gostam sudo
ou ssh
fazem). Versões futuras do bash
podem eventualmente fazer a otimização como em outros shells. Então você precisaria de algo como:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Para garantir que ainda haja um processo de shell extra com esse fd 3 aberto aguardando esse sudo
comando.
Observe que cat
não lerá nada (já que os processos não gravam em seu fd 3). Está lá apenas para sincronização. Ele fará apenas uma read()
chamada do sistema que retornará sem nada no final.
Na verdade, você pode evitar a execução cat
usando uma substituição de comando para fazer a sincronização de pipe:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Desta vez, é o shell, em vez disso, cat
que está lendo no canal, cuja outra extremidade está aberta nos fd 3 de cmd1
e cmd2
. Estamos usando uma atribuição de variável para que o status de saída de cmd1
esteja disponível em $?
.
Ou você pode fazer a substituição do processo manualmente, e então você pode até usar o sistema, sh
pois isso se tornaria a sintaxe padrão do shell:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
observe, como observado anteriormente, que nem todas as sh
implementações esperariam cmd1
após a cmd2
conclusão (embora isso seja melhor do que o contrário). Nesse momento, $?
contém o status de saída de cmd2
; embora bash
e zsh
disponibilize cmd1
o status de saída em ${PIPESTATUS[0]}
e $pipestatus[1]
respectivamente (consulte também a pipefail
opção em algumas conchas para que $?
possamos relatar a falha de outros componentes do tubo que não o anterior)
Observe que yash
há problemas semelhantes com o recurso de redirecionamento de processo . cmd1 >(cmd2)
seria escrito cmd1 /dev/fd/3 3>(cmd2)
lá. Mas cmd2
não é esperado e você também não pode wait
esperar por isso, e seu pid também não é disponibilizado na $!
variável. Você usaria as mesmas soluções alternativas de bash
.