Oui, bashcomme dans ksh(d'où vient la fonctionnalité), les processus à l'intérieur de la substitution de processus ne sont pas attendus (avant d'exécuter la commande suivante dans le script).
pour un <(...), c'est généralement bien comme dans:
cmd1 <(cmd2)
le shell attendra cmd1et cmd1attendra généralement cmd2en raison de sa lecture jusqu'à la fin du fichier sur le canal qui est substitué, et cette fin de fichier se produit généralement lors de la cmd2mort. C'est la même raison plusieurs obus (non bash) ne prennent pas la peine d' attendre pour cmd2en cmd2 | cmd1.
Car cmd1 >(cmd2), cependant, ce n'est généralement pas le cas, car c'est plus cmd2qui attend généralement cmd1là-bas, donc il sortira généralement après.
C'est fixé dans zshqui attend cmd2là (mais pas si vous écrivez comme cmd1 > >(cmd2)et cmd1n'est pas BuiltIn, utilisez {cmd1} > >(cmd2)plutôt comme documenté ).
kshn'attend pas par défaut, mais vous permet de l'attendre avec la fonction waitintégrée (cela rend également le pid disponible dans $!, bien que cela n'aide pas si vous le faites cmd1 >(cmd2) >(cmd3))
rc(avec la cmd1 >{cmd2}syntaxe), identique à ce que kshvous pouvez obtenir les pids de tous les processus d'arrière-plan avec $apids.
es(également avec cmd1 >{cmd2}) attend cmd2comme dans zsh, et attend également les redirections cmd2en <{cmd2}cours.
bashne rend pas disponible le pid de cmd2(ou plus exactement du sous-shell car il s'exécute cmd2dans un processus enfant de ce sous-shell même s'il s'agit de la dernière commande) $!, mais ne vous laisse pas l'attendre.
Si vous devez utiliser bash, vous pouvez contourner le problème en utilisant une commande qui attendra les deux commandes avec:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Cela fait les deux cmd1et cmd2ouvre leur fd 3 à un tuyau. catattendra la fin du fichier à l'autre extrémité, donc ne sortira généralement que lorsque les deux cmd1et cmd2seront morts. Et le shell attendra cette catcommande. Vous pouvez voir cela comme un filet pour attraper la fin de tous les processus en arrière-plan (vous pouvez l'utiliser pour d'autres choses démarrées en arrière-plan comme avec &, les coprocs ou même les commandes qui se mettent en arrière-plan à condition de ne pas fermer tous leurs descripteurs de fichiers comme le font généralement les démons ).
Notez que grâce à ce processus de sous-shell gaspillé mentionné ci-dessus, il fonctionne même si cmd2ferme son fd 3 (les commandes ne font généralement pas cela, mais certains aiment sudoou sshfont). Les futures versions de bashpourraient éventuellement faire l'optimisation comme dans d'autres shells. Ensuite, vous auriez besoin de quelque chose comme:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Pour vous assurer qu'il y a encore un processus shell supplémentaire avec ce fd 3 open en attente de cette sudocommande.
Notez que catcela ne lira rien (puisque les processus n'écrivent pas sur leur fd 3). Il est juste là pour la synchronisation. Il ne fera qu'un seul read()appel système qui reviendra sans rien à la fin.
Vous pouvez réellement éviter de courir caten utilisant une substitution de commande pour effectuer la synchronisation des canaux:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Cette fois, c'est le shell au lieu de catcela qui lit le tuyau dont l'autre extrémité est ouverte sur le fd 3 de cmd1et cmd2. Nous utilisons une affectation de variable afin que l'état de sortie de cmd1soit disponible dans $?.
Ou vous pouvez faire la substitution de processus à la main, puis vous pouvez même utiliser votre système shcar cela deviendrait la syntaxe standard du shell:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
mais notez comme indiqué précédemment que toutes les shimplémentations n'attendraient pas cmd1après la cmd2fin (bien que ce soit mieux que l'inverse). Cette fois, $?contient le statut de sortie de cmd2; cependant bashet zshrendre cmd1le statut de sortie de disponible dans ${PIPESTATUS[0]}et $pipestatus[1]respectivement (voir également l' pipefailoption dans quelques coquilles afin de $?pouvoir signaler la défaillance de composants de tuyaux autres que le dernier)
Notez qu'il yasha des problèmes similaires avec sa fonction de redirection de processus . cmd1 >(cmd2)serait écrit cmd1 /dev/fd/3 3>(cmd2)là-bas. Mais cmd2n'est pas attendu et vous ne pouvez pas non waitplus l'attendre et son pid n'est pas non plus disponible dans la $!variable. Vous utiliseriez les mêmes contournements que pour bash.