128 votes

Transférer uniquement STDERR à travers un filtre

Existe-t-il un moyen, en bash, de faire passer STDERR par un filtre avant de l'unifier avec STDOUT ? C'est-à-dire que je veux

STDOUT 
                       > terminal/file/whatever
STDERR  [ filter ] 

plutôt que

STDOUT 
           [ filter ]> terminal/file/whatever
STDERR

2 votes

9 votes

Ce texte mérite un vote positif simplement parce qu'il comprend un magnifique diagramme en ASCII-art.

72voto

Paul Rubel Points 13132

Voici un exemple, inspiré de Comment échanger des descripteurs de fichiers en bash ? . La sortie de a.out est la suivante, sans le préfixe 'STDXXX : '.

STDERR: stderr output
STDOUT: more regular

./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
more regular
stdErr output

Citation du lien ci-dessus :

  1. Sauvegarder d'abord le stdout en tant que &3 (&1 est dupliqué en 3)
  2. Envoyer ensuite stdout à stderr (&2 est dupliqué en 1)
  3. Envoyer stderr à &3 (stdout) (&3 est dupliqué en 2)
  4. fermer &3 (&- est dupliqué en 3)

2 votes

Ça ne marche pas pour moi. Finalement, j'ai réussi à le faire fonctionner avec 3>&2 2>&1 1>&3- .

6 votes

Attention Ceci suppose que le FD 3 n'est pas utilisé, et n'annule pas l'échange des descripteurs de fichiers 1 et 2, donc vous ne pouvez pas continuer à le transmettre à une autre commande. Voir cette réponse pour plus de détails et une solution de contournement. Pour une syntaxe beaucoup plus propre pour {ba,z}sh, voir cette réponse .

25voto

solidsnack Points 661

Une utilisation naïve de la substitution de processus semble permettre le filtrage de stderr séparément de stdout :

:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err

Notez que stderr sort sur stderr y stdout en stdout que nous pouvons voir en enveloppant le tout dans un autre sous-shell et en redirigeant vers des fichiers o y e

( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e

0 votes

Pourquoi le : ; au début ? J'ai essayé la ligne magique sans, et ça ne semble pas faire de différence.

2 votes

Certaines personnes utilisent $ comme une invite de commande. Ensuite, ils écrivent souvent des exemples de shell comme : $ cat /var/log/syslog | fgrep ... . Cependant, cette ligne n'est pas copiable en raison de l'utilisation de l'option $ . :; ressemble à une invite mais est fondamentalement un shell no-op ; vous pouvez donc sélectionner et coller la ligne entière en toute sécurité.

27 votes

Ok, mais vous pourriez simplement omettre le : ; et la ligne serait également copiable :) Pour moi, le : ; ne ressemble pas à un prompt, il ne rendait pas l'exemple plus clair (séparer les commandes de la sortie) mais prêtait à confusion. Bien que je comprenne votre point de vue et ne discutons pas de syntaxe/conventions.

8voto

Pecunifex Points 21

Je trouve l'utilisation de la substitution du processus bash plus facile à mémoriser et à utiliser car elle reflète l'intention originale presque mot pour mot. Par exemple :

$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr

utilise la première commande sed comme filtre sur stderr uniquement et la deuxième commande sed pour modifier la sortie jointe.

Notez que l'espace blanc après 2> est obligatoire pour que la commande soit analysée correctement.

7voto

signine Points 1108

La dernière partie de cette page du Guide avancé du script Bash est "rediriger uniquement stderr vers un tuyau".

# Rediriger uniquement stderr vers un pipe.

exec 3>&1                              # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # Close fd 3 for 'grep' (but not 'ls').
#              ^^^^   ^^^^
exec 3>&-                              # Now close it for the remainder of the script.

# Merci, S.C.

C'est peut-être ce que vous voulez. Sinon, une autre partie de l'ABSG devrait pouvoir vous aider, elle est excellente.

0 votes

Nous hésitons quelque peu à recommander l'ABSG comme référence, car il mélange documentation, prescription et opinion sans marquer clairement les différences. Certaines sections ont également un contenu douteux, bien que celle dont vous donnez le lien semble correcte.

2voto

wilhelmtell Points 25504

Jetez un coup d'œil aux tuyaux nommés :

$ mkfifo err
$ cmd1 2>err |cat - err |cmd2

0 votes

Ne le fera pas cat - err briser l'intercalation de stdout et stderr ?

0 votes

Martin - cela dépend. Si cmd1, cat, o cmd2 met en mémoire tampon la sortie, alors vous pourriez voir la sortie hors de la séquence.

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