Comment puis-je canaliser la sortie vers un autre process, mais conserver l'état d'erreur du premier process?

Duplicata possible:
Obtenir le code de sortie du process qui est envoyé à un autre

J'utilise la command line suivante (dans un makefile) pour diriger les messages d'erreur verbose de mon compilateur à travers un script perl qui les simplifie en quelque chose de lisible par l'homme:

g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl 

Malheureusement, cette approche "masque" la valeur d'erreur renvoyée par la command g++ . make n'a aucune idée que la command g++ a échoué, car tout ce qu'elle récupère est le résultat de l'erreur de la command perl .

Existe-t-il un moyen de canaliser la sortie et de conserver la condition d'erreur d'origine?

Au cas où cela ferait la différence: j'utilise GNU Make 3.81 et g ++ (GCC) 3.4.5 (mingw-vista special r3) dans une console MSYS exécutant GNU bash, version 2.04.0 (1) -release (i686-pc- msys) sur Windows XP.

Je ne suis pas sûr de ce que shell sh.exe fournit (puisqu'il existe plusieurs shells qui utilisent ce nom pour leurs exécutables Windows), mais si c'est bash ou similaire, vous pouvez utiliser le tableau $PIPESTATUS . Pour votre exemple, vous feriez:

 g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl echo "${PIPESTATUS[0]}" 

Bash a une option pipefail :

 The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit success- fully. 

Alors:

 set -o pipefail && $GCC_COMMAND | $PERL_COMMAND 

Make exécute chaque ligne d'un sous-shell pour chaque ligne , vous devez donc l'append au début de votre ligne gcc. Il y a peut-être un moyen d'get make pour exécuter juste une seule command avec pipefail set déjà mais je ne le sais pas.

Essayez d'append SHELL=/bin/bash dans Makefile ( Make devrait utiliser ceci )

Ou essayez:

 bash -o pipefail -c "$GCC_COMMAND | $PERL_COMMAND" 

Dans les shells traditionnels, le statut de la première command dans un pipeline n'est pas du tout rapporté au script. Seul le statut de la dernière command est disponible, dans $? .

Dans bash ≥3.0, si vous voulez arrêter une erreur dans le pipeline, utilisez l'option pipefail .

 g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl 

Plus généralement, en bash, le tableau de PIPESTATUS généralise $? pour couvrir toutes les commands du dernier pipeline.

 $ (exit 1) | (exit 2) | (exit 3); echo ${PIPESTATUS[@]} 1 2 3 

Zsh a la même caractéristique, seul le tableau est appelé pipestatus .

 % zsh -c '(exit 1) | (exit 2) | (exit 3); echo $pipestatus' 1 2 3 

Si vous êtes prêt à assumer bash (quel IIRC est le shell fourni par msys comme sh ), vous pouvez utiliser PIPESTATUS . Si vous ne l'êtes pas, vous pouvez faire passer le statut de sortie à l'environnement toplevel via le canal et faire sortir votre programme de filtrage avec l'état qu'il lit sur la dernière ligne d'input au lieu de l'utiliser comme input normale. C'est maladroit, mais ça peut être utile.

Dans les makefiles, il est relativement courant d'utiliser des files temporaires, traitant ici les messages du compilateur comme un file intermédiaire supplémentaire.

 %.otmp %.g++-log: %.cpp g++ -c $< -o $@tmp 2>&1 >$*.g++-log %.o: %.otmp %.g++-log perl /bin/gSTLFilt.pl <$*.g++-log mv $*.otmp $@