Question Comment diriger stderr, et pas stdout?


J'ai un programme qui écrit des informations à stdout et stderret j'ai besoin de grep à travers ce qui vient à stderr, sans tenir compte 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 être capable de le faire sans fichiers temporaires. Y a-t-il des astuces de tuyauterie intelligentes?


760
2018-02-26 15:53


origine


Réponses:


Première redirection 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 des E / S dans toute sa diversité, voir le chapitre sur Redirections dans le manuel de référence Bash.

Notez que la séquence des redirections d'E / S est interprétée de gauche à droite, mais que les canaux sont configurés avant l'interprétation des redirections d'E / S. Les descripteurs de fichier tels que 1 et 2 sont des références à des descriptions de fichiers ouvertes. 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 fait actuellement référence à (voir dup2() et open()). L'opération >/dev/null puis modifie le descripteur de fichier 1 afin qu'il se réfère à une description de fichier ouvert pour /dev/null, mais cela ne change rien au fait que le descripteur de fichier 2 fait référence à la description de fichier ouvert que le descripteur de fichier 1 désignait à l'origine, à savoir le tube.


902
2018-02-26 15:55



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

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

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


311
2018-03-04 18:18



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

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

Pour l'affaire en cours:

command 2> >(grep 'something') >/dev/null

172
2018-02-09 19:14



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

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

... puis tout stdout est conservé en tant que stdout et tout stderr est conservé en tant que stderr, mais vous ne verrez aucune ligne dans stderr commençant par la chaîne "quelque chose".

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


138
2018-04-10 21:05



Il est beaucoup plus facile de visualiser les choses si vous pensez à ce qui se passe réellement avec les "redirections" et les "tuyaux". Les redirections et les pipes dans bash font une chose: modifier où les descripteurs de fichiers de processus 0, 1 et 2 pointent (voir / proc / [pid] / fd / *).

Lorsqu'un tuyau ou "|" L'opérateur est présent sur la ligne de commande, la première chose à faire est que bash crée un fifo et pointe la FD 1 de la commande de gauche vers ce fifo, et pointe la FD 0 de la commande de droite vers le même fifo.

Ensuite, les opérateurs de redirection de 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é installé en premier, le FD1 (côté gauche) et le FD0 (côté droit) sont déjà changés de ce qu'ils auraient normalement été, et toute duplication de ceux-ci reflétera ce fait.

Par conséquent, lorsque vous tapez quelque chose comme ceci:

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 également pointé vers ce tuyau
  2. "commande FD2" est pointé vers où "commande FD1" pointe actuellement (le tuyau)
  3. "commande FD1" est pointé sur / dev / null

Ainsi, toutes les sorties que "commande" écrit dans sa FD 2 (stderr) se dirigent vers le canal et sont lues par "grep" de l'autre côté. Toutes les sorties que "command" écrit dans sa FD 1 (stdout) se retrouvent dans / 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 "la commande FD 1" et "grep FD 0" sont pointés dessus
  2. "commande FD 1" est pointé sur / dev / null
  3. "commande FD 2" est pointé vers où FD 1 pointe actuellement (/ dev / null)

Donc, tous les stdout et stderr de "command" vont à / dev / null. Rien ne va au tuyau, et ainsi "grep" se fermera sans rien afficher sur l'écran.

Notez également que les redirections (descripteurs de fichier) peuvent être en lecture seule (<), en écriture seule (>) ou en lecture-écriture (<>).

Une note finale Si un programme écrit quelque chose à FD1 ou FD2, est entièrement à la hauteur du programmeur. Une bonne pratique de programmation impose que les messages d'erreur passent à FD 2 et à la sortie normale à FD 1, mais vous trouverez souvent une programmation bâclée qui mélange les deux ou ignore la convention.


82
2017-08-20 18:09



Utilisez-vous bash? Si c'est le cas:

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

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


28
2018-04-18 21:56



Pour ceux qui veulent rediriger stdout et stderr de façon permanente vers des fichiers, grep sur stderr, mais gardez le stdout pour écrire des messages sur 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
2017-11-14 08:59



Cela redirigera command1 stderr vers command2 stdin, tout en laissant la commande stdout telle quelle.

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

Pris à partir de LDP


5
2017-10-07 07:39