Avec bash, comment canaliser l'erreur standard dans un autre processus?

138

Il est bien connu de canaliser la sortie standard d'un processus dans une autre entrée standard de processus:

proc1 | proc2

Mais que faire si je veux envoyer l'erreur standard de proc1 à proc2 et laisser la sortie standard aller à son emplacement actuel? Vous penseriez bashavoir une commande du type:

proc1 2| proc2

Mais, hélas, non. Y a-t-il un moyen de faire ça?

paxdiablo
la source
Vous pouvez faire une redirection aussi simple dans rc, qui est un autre shell. Par exemple: proc1 |[2] proc2. N'est-ce pas sympa? Pas bashdedans cependant.
Rolf

Réponses:

169

Il existe également une substitution de processus . Ce qui fait qu'un processus remplace un fichier.
Vous pouvez envoyer stderrvers un fichier comme suit:

process1 2> file

Mais vous pouvez remplacer le fichier par un processus comme suit:

process1 2> >(process2)

Voici un exemple concret qui envoie stderrà la fois à l'écran et s'ajoute à un fichier journal

sh myscript 2> >(tee -a errlog)
Écossais
la source
23
Cela répond correctement à la question posée et devrait être la réponse acceptée par @paxdiablo
mmlb
J'ai essayé ça. Cela n'a pas fonctionné ( weston --help 2> >(less)), et cela a brisé ma coquille, j'ai dû quitter et me reconnecter.
Rolf
1
@Rolf si les deux weston --helpet lesss'attendent à avoir une interaction avec le clavier mais qu'un seul d'entre eux la reçoit, alors vous pouvez être dans une situation délicate. Essayez grepplutôt de faire des tests avec quelque chose comme . De plus, vous constaterez peut-être que les deux entrées souris / clavier vont de toute façon à la deuxième commande plutôt qu'à Weston.
BeowulfNode42
88

Vous pouvez utiliser l'astuce suivante pour permuter stdout et stderr. Ensuite, vous utilisez simplement la fonctionnalité de canal standard.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Pourvu stdoutet stderrtous les deux pointés vers le même endroit au départ, cela vous donnera ce dont vous avez besoin.

Ce que fait le x>ybit, c'est de changer le descripteur de fichier xafin qu'il envoie maintenant ses informations à l'endroit où le descripteur de fichier ypointe actuellement. Pour notre cas spécifique:

  • 3>&1crée un nouveau handle 3qui sortira vers le handle actuel1 (stdout d'origine), juste pour le sauvegarder quelque part pour le dernier point ci-dessous.
  • 1>&2modifie le handle 1(stdout) en sortie vers le handle actuel2 (stderr d'origine).
  • 2>&3-modifie le handle 2(stderr) pour afficher le handle actuel3 (stdout d'origine) puis ferme le handle 3(via le -à la fin).

C'est en fait la commande swap que vous voyez dans les algorithmes de tri:

temp   = value1;
value1 = value2;
value2 = temp;
paxdiablo
la source
3
Quelle est la valeur d'utiliser 1>&2-ici plutôt que simplement 1>&2? Je ne comprends pas pourquoi nous voudrions fermer fd 2, si nous allons simplement le rouvrir / le réaffecter immédiatement.
dubiousjim
1
@dubiousjim, aucun avantage dans ce cas particulier, je suppose que je l'ai fait juste pour être cohérent - fermer le descripteur de fichier 3 est une bonne idée pour le libérer.
paxdiablo
Bon point, @ovgolovin, je ne peux pas croire que personne ne l'ait repris en sept mois depuis que j'ai fait cette modification. Fixé selon votre suggestion.
paxdiablo
essayer de faire fonctionner le make de gcc (qui est colorisé sur mon système) avec ceci "(make 3> & 1 1> & 2- 2> & 3-) | less -R" while "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "fonctionne comme prévu.
non synchronisé
Il semble que vos explications soient inversées pour les deux secondes redirections. 1> & 2- définit le descripteur de fichier 2 (stderr d'origine) pour gérer 1 (stdout d'origine) 2> & 3- définit le descripteur de fichier 3 (stdout copié) sur 2 (stderr d'origine). Veuillez me corriger si je me trompe. btw, je suppose que le tiret sur 2 sert à empêcher l'envoi de nouvelles données stderr à ce tampon pendant qu'il est rempli avec les données de stdout.
aghsmith
70

Bash 4 a cette fonctionnalité:

Si «| &» est utilisé, l'erreur standard de commande1 est connectée à l'entrée standard de commande2 via le tube; c'est un raccourci pour 2> & 1 |. Cette redirection implicite de l'erreur standard est effectuée après toutes les redirections spécifiées par la commande.

zsh a également cette fonctionnalité.

-

Avec d'autres shells / plus anciens, entrez simplement ceci explicitement comme

FirstCommand 2> & 1 | AutreCommande

Suspendu jusqu'à nouvel ordre.
la source
14
À la lecture de la documentation, cela fait à la fois une erreur standard et une sortie par opposition à stderr, mais c'est bon à savoir. Il est temps de commencer à regarder bash 4, je pense.
paxdiablo
Le manuel bash actuel lit "Si | & est utilisé, l'erreur standard de la commande, en plus de sa sortie standard, est connectée à l'entrée standard de la commande2". Ce n'est explicitement pas ce que souhaite le PO.
Peter - Réintégrer Monica le
@ PeterA.Schneider: L'OP dit "laissez la sortie standard aller à son emplacement actuel", ce qui peut être ambigu.
Suspendu jusqu'à nouvel ordre.
Je ne vois aucune ambiguïté. Votre suggestion (1) associe les deux courants. (2) OtherCommandécrit les données combinées quelque part, peut-être ailleurs. Ce ne sont donc pas les mêmes données, et elles vont potentiellement ailleurs. C'est à peu près le contraire du souhait du PO, n'est-ce pas?
Peter - Réintégrer Monica le
@ PeterA.Schneider: Où est l'emplacement actuel de la sortie standard? Si les proc1sorties vers stdout et stderr et que vous voulez que stderr aille vers le stdin de proc2(c'est là que va le stdout de proc1), alors ma réponse accomplit cela. J'ai donné au PO ce qu'il avait demandé , peut-être pas ce qu'il voulait demander. C'est là que réside l'ambiguïté potentielle. L'OP a accepté la réponse qui permute stdout et stderr ce qui n'est pas ce qu'il a demandé.
Suspendu jusqu'à nouvel ordre.
27

L'échange est excellent car il résout le problème. Juste au cas où vous n'auriez même pas besoin de la sortie standard d'origine, vous pouvez le faire de cette façon:

proc1 2>&1 1>/dev/null | proc2

L'ordre est vital; vous ne voudriez pas:

proc1 >/dev/null 2>&1 | proc1

Comme cela redirigera tout vers /dev/null!

kccqzy
la source
0

Aucun de ceux-ci n'a vraiment très bien fonctionné. La meilleure façon que j'ai trouvée de faire ce que vous vouliez est:

(command < input > output) 2>&1 | less

Cela ne fonctionne que dans les cas où commandaucune saisie au clavier n'est nécessaire. par exemple:

(gzip -d < file.gz > file) 2>&1 | less

mettrait les erreurs gzip en moins

sbingner
la source