Sim, em bash como em ksh (de onde vem o recurso), os processos dentro da substituição do processo não são esperados (antes de executar o próximo comando no script).
por <(...) , geralmente está bem como em:
cmd1 <(cmd2)
o shell estará aguardando por cmd1 e cmd1 estará normalmente aguardando cmd2 em virtude de ler até o final do arquivo no canal substituído e esse fim de arquivo normalmente acontece quando cmd2 morre. Essa é a mesma razão pela qual várias shells (não bash ) não se incomodam em esperar por cmd2 in cmd2 | cmd1 .
Por cmd1 >(cmd2) , no entanto, esse geralmente não é o caso, já que é mais cmd2 que normalmente espera por cmd1 , então geralmente sairá depois.
Isso foi corrigido em zsh , que aguarda cmd2 lá (mas não se você o escrever como cmd1 > >(cmd2) e cmd1 não está embutido, use {cmd1} > >(cmd2) como documented ).
ksh não espera por padrão, mas permite que você espere por ele com o wait incorporado (ele também disponibiliza o pid em $! , embora isso não ajude se você usar cmd1 >(cmd2) >(cmd3) )
rc (com a sintaxe cmd1 >{cmd2} ), igual a ksh , exceto que você pode obter os pids de todos os processos em segundo plano com $apids .
es (também com cmd1 >{cmd2} ) aguarda cmd2 como em zsh e também espera por cmd2 em <{cmd2} process redirections.
bash faz o pid de cmd2 (ou mais exatamente do subshell, já que executa cmd2 em um processo filho desse subshell, embora seja o último comando lá) disponível em $! , mas não deixa você esperar por isso.
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 com que ambos cmd1 e cmd2 tenham seu fd 3 aberto para um pipe. cat aguardará o final do arquivo na outra extremidade, portanto, normalmente só sairá quando cmd1 e cmd2 estiverem inativos. E o shell aguardará esse comando cat . 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 iniciados em segundo plano como & , coprocs ou até mesmo comandos que antecedem eles mesmos, se não fecharem todos os descritores de arquivo como daemons normalmente fazem).
Note que, graças ao processo de subshell desperdiçado mencionado acima, ele funciona mesmo se cmd2 fechar seu fd3 (os comandos geralmente não fazem isso, mas alguns como sudo ou ssh do). Versões futuras de bash podem eventualmente fazer a otimização como em outras shells. Então você precisaria de algo como:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Para ter certeza de que ainda há um processo de shell extra com o fd 3 aberto esperando pelo comando sudo .
Note que cat não lê nada (já que os processos não escrevem no fd 3). Está lá apenas para sincronização. Ele fará apenas uma chamada de sistema read() que retornará sem nada no final.
Você pode realmente evitar a execução de cat usando uma substituição de comando para fazer a sincronização do pipe:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Desta vez, é o shell em vez de cat que está lendo o canal cuja outra extremidade está aberta no 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ê poderia fazer a substituição do processo manualmente, e então você poderia até mesmo usar o sh do seu sistema como se fosse a sintaxe padrão do shell:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
no entanto observe, como observado anteriormente, que nem todas as implementações sh esperariam por cmd1 após cmd2 ter terminado (embora seja melhor do que o contrário). Nesse momento, $? contém o status de saída de cmd2 ; embora bash e zsh disponibilizem o status de saída de cmd1 em ${PIPESTATUS[0]} e $pipestatus[1] respectivamente (consulte também a opção pipefail em alguns shells, portanto $? pode relatar a falha de outros componentes do duto que o último)
Observe que yash tem problemas semelhantes com o recurso redirecionamento do processo. cmd1 >(cmd2) seria escrito cmd1 /dev/fd/3 3>(cmd2) lá. Mas cmd2 não está aguardando e você não pode usar wait para esperar por ele e seu pid também não está disponível na variável $! . Você usaria o mesmo trabalho em torno de bash .