84 votes

diriger stdout et stderr vers deux processus différents dans un script shell?

J'ai une pipline en train de faire juste

  command1 | command2
 

Ainsi, stdout de commande1 va à commande2, tandis que stderr de commande1 ira au terminal (ou où que soit stdout du shell).

Comment puis-je diriger le stderr de command1 vers un troisième processus ( command3 ) alors que stdout est toujours sur command2?

81voto

olibre Points 6069

Utiliser un autre descripteur de fichier

{ command1 2>&3 | command2; } 3>&1 1>&2 | command3

Vous pouvez utiliser jusqu'à 7 autres descripteurs de fichier: de 3 à 9.
Si vous voulez plus d'explications, veuillez demander, je peux l'expliquer ;-)

Test

{ { echo a; echo >&2 b; } 2>&3 | sed >&2 's/$/1/'; } 3>&1 1>&2 | sed 's/$/2/'

sortie:

b2
a1

Exemple

Produire deux fichiers journaux:
1. stderr seulement
2. stderr et stdout

{ { { command 2>&1 1>&3; } | tee err-only.log; } 3>&1; } > err-and-stdout.log

Si command est echo "stdout"; echo "stderr" >&2 alors nous pouvons le tester comme ça:

$ { { { echo out>&3;echo err>&1;}| tee err-only.log;} 3>&1;} > err-and-stdout.log
$ head err-only.log err-and-stdout.log
==> err-only.log <==
err

==> err-and-stdout.log <==
out
err

17voto

olibre Points 6069

Il suffit de rediriger stderr vers stdout

 { command1 | command2; } 2>&1 | command3
 

Attention: commnd3 lira également command2 stdout (le cas échéant).
Pour éviter cela, vous pouvez ignorer commnd2 stdout:

 { command1 | command2 >/dev/null; } 2>&1 | command3
 

Cependant, pour garder command2 stdout (par exemple dans le terminal),
alors s'il vous plaît se référer à mon autre réponse plus complexe.

Tester

 { { echo -e "a\nb\nc" >&2; echo "----"; } | sed 's/$/1/'; } 2>&1 | sed 's/$/2/'
 

sortie:

 a2
b2
c2
----12
 

1voto

FatalError Points 19772

Le même effet peut être réalisé assez facilement avec un fifo. Je ne suis pas au courant de la tuyauterie de la syntaxe pour le faire (même si ce serait chouette de voir un). C'est la façon dont vous pourriez le faire avec une fifo.

Tout d'abord, quelque chose qui imprime à la fois stdout et stderr, outerr.sh:

#!/bin/bash

echo "This goes to stdout"
echo "This goes to stderr" >&2

Ensuite, nous pouvons faire quelque chose comme ceci:

$ mkfifo err
$ wc -c err &
[1] 2546
$ ./outerr.sh 2>err | wc -c
20
20 err
[1]+  Done                    wc -c err

De cette façon, vous configurez le port d'écoute pour stderr sortie en premier et il bloque jusqu'à ce qu'un écrivain qui se passe dans la commande suivante, en utilisant la syntaxe 2>err. Vous pouvez voir que chaque wc -c obtenu 20 caractères d'entrée.

N'oubliez pas de nettoyer la fifo après vous avez terminé, si vous n'avez pas envie de traîner (c - rm). Si l'autre veut d'entrée de commande sur stdin et non pas un fichier arg, vous pouvez utiliser la redirection d'entrée comme wc -c < err trop.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X