Comment canaliser stderr sans canalisation stdout

24

Comment canaliser le flux d'erreur standard sans canaliser le flux de sortie standard?

Je sais que cette commande fonctionne, mais elle écrit également la norme.

Command 2>&1 | tee -a $LOG

Comment puis-je obtenir uniquement l'erreur standard?

Remarque: Ce que je veux en sortir, c'est simplement écrire le flux stderr dans un journal et écrire à la fois stderr et stdout sur la console.

Traverser
la source

Réponses:

26

Pour ce faire, utilisez un descripteur de fichier supplémentaire pour basculer stderr et stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

Fondamentalement, cela fonctionne, ou du moins je pense que cela fonctionne, comme suit:
Les réorientations sont évaluées de gauche à droite.

3>&1 Crée un nouveau descripteur de fichier, 3 une copie (copie) de fd 1 (stdout).

1>&2 Faire de stdout (1) un doublon de fd 2 (stderr)

2>&3 Faites fd 2, une copie (copie) de 3, qui était auparavant une copie de stdout.

Alors maintenant, stderr et stdout sont commutés.

| tee foo.file tee duplique le descripteur de fichier 1 qui a été transformé en stderr.

Kyle Brandt
la source
Oh, non testé avec ksh, fonctionne avec bash si ...
Kyle Brandt
Merci, fonctionne aussi en ksh. Je pense que la plupart des tuyaux et des flux sont des standards posix.
C. Ross
"Copier" n'est pas vraiment correct - Voir la réponse de @ Guasqueño.
Kyle Brandt
Cela fonctionne également dans Windows avec tee.exeinstallé :)
Acorn
13

La commande Unix / Linux de Kyle fait le travail de commutation du STDERR avec le STDOUT; cependant, l'explication n'est pas tout à fait correcte. Les opérateurs de redirection ne font pas de copie ou de duplication, ils redirigent simplement le flux dans une direction différente.

Réécrire la commande de Kyle en déplaçant temporairement le 3> & 1 à la fin, faciliterait la compréhension du concept:

find /var/log  1>&2  2>&3  3>&1  

Écrit de cette façon cependant, Linux afficherait une erreur car & 3 n'existe pas encore car il se trouve avant 3> & 1. 3> quelque chose est un moyen de déclarer (définir) que nous allons utiliser un troisième tuyau, il faut donc le localiser avant de faire couler de l'eau dans ce tuyau, par exemple la façon dont Kyle l'a écrit. Essayez cette autre façon juste pour le plaisir:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

Ne pas avoir de moyen de faire des copies est une honte. Vous ne pouvez pas faire des choses comme "3> & 1 3> & 2" dans la même commande, car Linux n'utilisera que le premier trouvé et rejettera le second.

Je n'ai pas (encore) trouvé de moyen d'envoyer à la fois l'erreur et la sortie normale dans un fichier et d'envoyer également une copie de l'erreur à la sortie standard avec une seule commande. Par exemple, j'ai un travail cron que je veux que les deux sorties (erreur et standard) soient enregistrées dans un fichier journal et que l'erreur disparaisse également pour envoyer un message électronique à mon blackBerry. Je peux le faire avec deux commandes en utilisant "tee" mais l'erreur ne s'affiche pas dans le bon ordre parmi la ligne de sortie régulière du fichier. C'est la façon laide dont j'ai résolu le problème:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Notez que je dois utiliser log1 deux fois et que je dois ajouter dans les deux cas, le premier en utilisant l'option "-a" pour la commande "tee" et le second en utilisant ">>".

En faisant un journal de chat1, vous obtenez ce qui suit:

STD1
STD2
-bash: sdfr: command not found

Notez que l'erreur ne s'affiche pas comme il se doit sur la deuxième ligne.

Guasqueño
la source
Correction impressionnante !
Kyle Brandt
Découvrez zsh et mult_iosoption ( activé par défaut) pour pouvoir rediriger un FD plusieurs fois.
Tom Hale
2

selon la page de manuel de ksh (pdksh), vous pouvez simplement faire:

Commande 2> & 1> / dev / null | chat -n

c'est-à-dire dup stderr vers stdout, rediriger stdout vers / dev / null, puis rediriger vers 'cat -n'

fonctionne sur pdksh sur mon système:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
foo

$ errorecho foo> / dev / null # devrait toujours s'afficher même avec stdout redirigé
foo

$ errorecho foo 2> & 1> / dev / null | chat -n
     1 foo
$   
cas
la source
Fonctionne également avec BusyBox
Udo G
1

Je l'ai fait fonctionner comme vous l'avez toujours voulu car j'en avais également besoin et affiné votre commande. maintenant pour moi, cela fonctionne correctement en utilisant bash 3.2 sur Debian Squeeze en utilisant ce

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

alors que log1 enregistre stdout et stderr et log2 enregistre uniquement stderr et rien d'autre qu'il met à l'écran.

martinseener
la source