Oui, bash
comme 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 cmd1
et cmd1
attendra généralement cmd2
en 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 cmd2
mort. C'est la même raison plusieurs obus (non bash
) ne prennent pas la peine d' attendre pour cmd2
en cmd2 | cmd1
.
Car cmd1 >(cmd2)
, cependant, ce n'est généralement pas le cas, car c'est plus cmd2
qui attend généralement cmd1
là-bas, donc il sortira généralement après.
C'est fixé dans zsh
qui attend cmd2
là (mais pas si vous écrivez comme cmd1 > >(cmd2)
et cmd1
n'est pas BuiltIn, utilisez {cmd1} > >(cmd2)
plutôt comme documenté ).
ksh
n'attend pas par défaut, mais vous permet de l'attendre avec la fonction wait
inté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 ksh
vous pouvez obtenir les pids de tous les processus d'arrière-plan avec $apids
.
es
(également avec cmd1 >{cmd2}
) attend cmd2
comme dans zsh
, et attend également les redirections cmd2
en <{cmd2}
cours.
bash
ne rend pas disponible le pid de cmd2
(ou plus exactement du sous-shell car il s'exécute cmd2
dans 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 cmd1
et cmd2
ouvre leur fd 3 à un tuyau. cat
attendra la fin du fichier à l'autre extrémité, donc ne sortira généralement que lorsque les deux cmd1
et cmd2
seront morts. Et le shell attendra cette cat
commande. 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 cmd2
ferme son fd 3 (les commandes ne font généralement pas cela, mais certains aiment sudo
ou ssh
font). Les futures versions de bash
pourraient é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 sudo
commande.
Notez que cat
cela 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 cat
en 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 cat
cela qui lit le tuyau dont l'autre extrémité est ouverte sur le fd 3 de cmd1
et cmd2
. Nous utilisons une affectation de variable afin que l'état de sortie de cmd1
soit disponible dans $?
.
Ou vous pouvez faire la substitution de processus à la main, puis vous pouvez même utiliser votre système sh
car 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 sh
implémentations n'attendraient pas cmd1
après la cmd2
fin (bien que ce soit mieux que l'inverse). Cette fois, $?
contient le statut de sortie de cmd2
; cependant bash
et zsh
rendre cmd1
le statut de sortie de disponible dans ${PIPESTATUS[0]}
et $pipestatus[1]
respectivement (voir également l' pipefail
option dans quelques coquilles afin de $?
pouvoir signaler la défaillance de composants de tuyaux autres que le dernier)
Notez qu'il yash
a des problèmes similaires avec sa fonction de redirection de processus . cmd1 >(cmd2)
serait écrit cmd1 /dev/fd/3 3>(cmd2)
là-bas. Mais cmd2
n'est pas attendu et vous ne pouvez pas non wait
plus l'attendre et son pid n'est pas non plus disponible dans la $!
variable. Vous utiliseriez les mêmes contournements que pour bash
.