Comment pipe stderr, et pas stdout?

j'ai un programme qui écrit des informations à stdout et stderr , et j'ai besoin de grep à travers ce qui vient à stderr , tout en ignorant stdout .

je peux bien sûr le faire en 2 étapes:

command > /dev/null 2> temp.file
grep 'something' temp.file

mais je préférerais pouvoir le faire sans fichiers temp. Existe-il des smart tuyauterie astuces?

786
demandé sur Jonathan Leffler 2010-02-26 18:53:27
la source

10 ответов

rediriger d'abord stderr vers stdout - le tuyau; puis rediriger stdout vers /dev/null (sans changer où stderr va):

command 2>&1 >/dev/null | grep 'something'

pour les détails de la redirection I/O dans toute sa variété, voir le chapitre Redirections dans le manuel de référence de Bash.

noter que la séquence des redirections d'e/s est interprétée de gauche à droite, mais les pipes sont configurées avant que les redirections d'e/s soient interprétées. Fichier les descripteurs tels que 1 et 2 sont des références à des descriptions de fichiers ouverts. L'opération 2>&1 rend le descripteur de fichier 2 aka stderr se référer à la même description de fichier ouvert que le descripteur de fichier 1 aka stdout se réfère actuellement à (voir dup2() et open() ). L'opération >/dev/null modifie alors le descripteur de fichier 1 de sorte qu'il se réfère à une description de fichier ouvert pour /dev/null , mais cela ne change pas le fait que le fichier le descripteur 2 fait référence à la description du fichier ouvert sur lequel le descripteur de fichier 1 pointait à l'origine, à savoir la pipe.

931
répondu Jonathan Leffler 2018-09-04 20:14:01
la source

ou pour échanger la sortie de stderr et stdout sur l'utilisation: -

command 3>&1 1>&2 2>&3

crée un nouveau descripteur de fichier (3) et l'assigne au même endroit que 1 (stdout), puis assigne fd 1 (stdout) au même endroit que fd 2 (stderr) et finalement assigne fd 2 (stderr) au même endroit que fd 3 (stdout). Stderr est maintenant disponible en stdout et vieux stdout conservé à stderr. Cela peut être exagéré, mais avec un peu de chance donne plus de détails sur les descripteurs de fichiers bash (il y a 9 pour chaque processus).

313
répondu Kramish 2018-04-15 12:09:12
la source

dans Bash, vous pouvez également rediriger vers un sous-puits en utilisant substitution de processus :

command > >(stdlog pipe)  2> >(stderr pipe)

pour la présente affaire:

command 2> >(grep 'something') >/dev/null
177
répondu Rich Johnson 2016-06-02 23:03:37
la source

combinant le meilleur de ces réponses, si vous le faites:

command 2> >(grep -v something 1>&2)

...alors tout stdout est préservé comme stdout et tout stderr est préservé comme stderr, mais vous ne verrez aucune ligne dans stderr contenant la chaîne"something".

ceci a l'avantage unique de ne pas inverser ou rejeter stdout et stderr, ni les écraser ensemble, ni utiliser des fichiers temporaires.

142
répondu Pinko 2018-08-22 06:03:56
la source

il est beaucoup plus facile de visualiser les choses si vous pensez à ce qui se passe vraiment avec" redirections "et" pipes."Redirige et pipes dans bash faites une chose: modifiez où les descripteurs de fichier 0, 1 et 2 pointent vers (Voir /proc/[pid]/fd/*).

Lorsqu'un opérateur pipe ou " | " est présent sur la ligne de commande, la première chose à faire est que bash crée un fifo et pointe le FD 1 de la commande du côté gauche vers ce fifo, et pointe le droit la commande latérale est FD 0 pour le même fifo.

ensuite, les opérateurs de redirection pour chaque côté sont évalués de gauche à droite , et les paramètres actuels sont utilisés chaque fois que la duplication du descripteur se produit. Ceci est important parce que depuis que le tuyau a été mis en place en premier, Le FD1 (côté gauche) et le FD0 (côté droit) sont déjà changés de ce qu'ils auraient pu être normalement, et toute duplication de ceux-ci reflétera ce fait.

Par conséquent, lorsque vous tapez quelque chose comme ce qui suit:

command 2>&1 >/dev/null | grep 'something'

Voici ce qui se passe, dans l'ordre:

  1. un tuyau (fifo) est créé. "commande FD1" est pointé sur ce tuyau. "grep FD0" est aussi pointé vers ce tuyau
  2. de la commande "FD2" est dirigé à l'endroit où la commande "FD1" actuellement, les points (la pipe)
  3. de la commande "FD1" est dirigé vers /dev/null

donc, tous sortie que "commande" écrit à son FD 2 (stderr) fait son chemin au tuyau et est lu par "grep" de l'autre côté. Toute la sortie qui" commande " écrit à son FD1 (stdout) fait son chemin vers /dev/null.

si à la place, vous exécutez ce qui suit:

command >/dev/null 2>&1 | grep 'something'

voici ce qui se passe:

  1. un tuyau est créé et "commande FD 1" et "grep FD 0" sont pointés vers lui
  2. de la commande "FD 1" est souligné / dev / null
  3. de la commande "FD 2" est dirigé vers où FD 1 pointe actuellement (/dev/null)

Donc, tous les stdout et stderr de "commande" aller à /dev/null. Rien ne va à la pipe, et donc "grep" va fermer sans rien afficher sur l'écran.

notez Également que des redirections (descripteurs de fichiers) peuvent être en lecture seule (<), en écriture seule (>), ou en lecture-écriture (<>).

un dernier mot. Si un programme écrit quelque chose à FD1 ou FD2, dépend entièrement du programmeur. Les bonnes pratiques de programmation dictent que les messages d'erreur doivent aller à FD 2 et la sortie normale à FD 1, mais vous trouverez souvent une programmation négligée qui mélange les deux ou ignore la convention.

86
répondu Michael Martinez 2013-08-20 22:18:28
la source

utilisez-vous bash? Dans l'affirmative:

command >/dev/null |& grep "something"

http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

28
répondu Ken Sharp 2014-04-19 01:56:16
la source

pour ceux qui veulent rediriger stdout et stderr de façon permanente vers les fichiers, grep sur stderr, mais garder le stdout pour écrire des messages à un tty:

# save tty-stdout to fd 3
exec 3>&1
# switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
# goes to the std.out
echo "my first message" >&1
# goes to the std.err
echo "a error message" >&2
# goes nowhere
echo "this nasty_msg won't appear anywhere" >&2
# goes to the tty
echo "a message on the terminal" >&3
9
répondu JBD 2013-04-04 12:05:20
la source

redirigera la commande 1 stderr vers la commande 2 stdin, tout en laissant la commande 1 stdout telle quelle.

exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-

tiré de LDP

5
répondu theDolphin 2014-10-07 11:39:05
la source

je viens de trouver une solution pour envoyer stdout à une commande et stderr à une autre, en utilisant des pipes nommées.

voilà.

mkfifo stdout-target
mkfifo stderr-target
cat < stdout-target | command-for-stdout &
cat < stderr-target | command-for-stderr &
main-command 1>stdout-target 2>stderr-target

c'est probablement une bonne idée d'enlever les pipes nommées par la suite.

1
répondu Tripp Kinetics 2018-08-09 21:35:48
la source

j'essaie de suivre, de trouver du travail en tant que bien,

command > /dev/null 2>&1 | grep 'something'
-3
répondu lasteye 2018-08-13 11:07:05
la source

Autres questions sur bash grep pipe stdout stderr