J'ai donc voulu apporter une réponse comme celle de lesmana, mais je pense que la mienne est peut-être une solution pure-Bourne-shell un peu plus simple et légèrement plus avantageuse:
# You want to pipe command1 through command2:
exec 4>&1
exitstatus=`{ { command1; printf $? 1>&3; } | command2 1>&4; } 3>&1`
# $exitstatus now has command1's exit status.
Je pense que cela s'explique mieux de l'intérieur - command1 exécutera et imprimera sa sortie régulière sur stdout (descripteur de fichier 1), puis une fois cela fait, printf exécutera et imprimera le code de sortie d'icommand1 sur sa stdout, mais cette stdout est redirigée vers descripteur de fichier 3.
Pendant que command1 est en cours d'exécution, sa sortie standard est dirigée vers command2 (la sortie de printf ne parvient jamais à command2 car nous l'envoyons vers le descripteur de fichier 3 au lieu de 1, qui est ce que le tuyau lit). Ensuite, nous redirige la sortie de command2 vers le descripteur de fichier 4, afin qu'il reste également en dehors du descripteur de fichier 1 - parce que nous voulons que le descripteur de fichier 1 soit gratuit un peu plus tard, car nous ramènerons la sortie printf du descripteur de fichier 3 dans le descripteur de fichier 1 - parce que c'est ce que la substitution de commandes (les backticks) capturera et c'est ce qui sera placé dans la variable.
Le dernier morceau de magie est que exec 4>&1
nous l'avons d' abord fait comme une commande distincte - il ouvre le descripteur de fichier 4 comme une copie de la sortie standard du shell externe. La substitution de commandes capturera tout ce qui est écrit sur la norme du point de vue des commandes à l'intérieur - mais puisque la sortie de command2 va dans le descripteur de fichier 4 en ce qui concerne la substitution de commandes, la substitution de commandes ne la capture pas - cependant une fois obtient "hors" de la substitution de commande, il va effectivement toujours au descripteur de fichier global du script 1.
(La exec 4>&1
doit être une commande distincte car de nombreux shells courants ne l'aiment pas lorsque vous essayez d'écrire dans un descripteur de fichier à l'intérieur d'une substitution de commande, qui est ouvert dans la commande "externe" qui utilise la substitution. moyen portable le plus simple de le faire.)
Vous pouvez le regarder d'une manière moins technique et plus ludique, comme si les sorties des commandes se dépassaient les unes les autres: command1 redirige vers command2, puis la sortie du printf saute par-dessus la commande 2 afin que la commande2 ne l'attrape pas, puis la sortie de la commande 2 saute au-dessus et en dehors de la substitution de commande juste au moment où printf atterrit juste à temps pour être capturé par la substitution afin qu'il finisse dans la variable, et la sortie de command2 continue à être joyeusement écrite sur la sortie standard, tout comme dans un tuyau normal.
Aussi, si je comprends bien, $?
contiendra toujours le code retour de la deuxième commande dans le canal, car les affectations de variables, les substitutions de commandes et les commandes composées sont toutes effectivement transparentes pour le code retour de la commande à l'intérieur, donc l'état de retour de command2 devrait se propager - ceci, et ne pas avoir à définir de fonction supplémentaire, c'est pourquoi je pense que cela pourrait être une meilleure solution que celle proposée par lesmana.
Selon les mises en garde que mentionne lesmana, il est possible que command1 finisse par utiliser des descripteurs de fichiers 3 ou 4, donc pour être plus robuste, vous feriez:
exec 4>&1
exitstatus=`{ { command1 3>&-; printf $? 1>&3; } 4>&- | command2 1>&4; } 3>&1`
exec 4>&-
Notez que j'utilise des commandes composées dans mon exemple, mais les sous-coquilles (l'utilisation à la ( )
place de { }
fonctionnera également, bien que peut-être moins efficace.)
Les commandes héritent des descripteurs de fichiers du processus qui les lance, de sorte que la deuxième ligne entière héritera du descripteur de fichiers quatre, et la commande composée suivie de 3>&1
héritera du descripteur de fichiers trois. Ainsi, la commande 4>&-
s'assure que la commande interne composée n'héritera pas du descripteur de fichier quatre et 3>&-
qu'elle n'héritera pas du descripteur de fichier trois, de sorte que command1 obtient un environnement plus propre et plus standard. Vous pouvez également déplacer l'intérieur à 4>&-
côté du 3>&-
, mais je pense pourquoi ne pas limiter autant que possible sa portée.
Je ne sais pas combien de fois les choses utilisent directement les descripteurs de fichiers trois et quatre - je pense que la plupart du temps, les programmes utilisent des appels système qui renvoient des descripteurs de fichiers non utilisés pour le moment, mais parfois le code écrit directement dans le descripteur de fichier 3, je guess (je pourrais imaginer un programme vérifiant un descripteur de fichier pour voir s'il est ouvert, et l'utilisant s'il l'est, ou se comportant différemment en conséquence s'il ne l'est pas). Il est donc préférable de garder ce dernier à l'esprit et de l'utiliser pour les cas à usage général.