1238 votes

Comment canaliser stderr, et non stdout ?

J'ai un programme qui écrit des informations sur 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 temporaires. Une astuce de tuyauterie intelligente ?

2 votes

Une question similaire, mais en retenant la sortie : unix.stackexchange.com/questions/3514/

0 votes

Cette question s'adressait à Bash, mais il est utile de mentionner ce lien. article pour la coquille Bourne / Almquist.

18 votes

Je m'attendais à quelque chose comme ça : command 2| othercommand . Bash est si parfait que son développement s'est arrêté en 1982, donc nous ne verrons jamais cela dans bash, j'en ai peur.

1513voto

Jonathan Leffler Points 299946

Rediriger stderr vers stdout et ensuite stdout vers /dev/null :

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

Pour les détails de la redirection des E/S dans toute sa variété, voir le chapitre sur les Redirections dans le manuel de référence de Bash.

56 votes

Je suis tombé sur /dev/stdout /dev/stderr /dev/stdin l'autre jour, et je suis curieux de savoir si ce sont de bonnes façons de faire la même chose ? J'ai toujours pensé que 2>&1 était un peu obfusqué. Donc quelque chose comme : command 2> /dev/stdout 1> /dev/null | grep 'something'

18 votes

Vous pourriez utiliser /dev/stdout et al, ou utiliser /dev/fd/N . Ils seront légèrement moins efficaces à moins que l'interpréteur de commandes ne les traite comme des cas particuliers ; la notation numérique pure n'implique pas d'accéder aux fichiers par leur nom, mais l'utilisation des périphériques implique une recherche par nom de fichier. On peut se demander si l'on peut mesurer cela. J'aime le caractère succinct de la notation numérique - mais je l'utilise depuis si longtemps (plus d'un quart de siècle ; ouch !) que je ne suis pas qualifié pour juger de ses mérites dans le monde moderne.

0 votes

Haha, c'est juste, Jonathan. Je n'avais pas réalisé qu'il y avait un gain d'efficacité avec 2>&1. Merci de l'avoir souligné

405voto

Kramish Points 1361

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'assigne au même endroit que 1 (stdout), puis assigne fd 1 (stdout) au même endroit que fd 2 (stderr) et enfin assigne fd 2 (stderr) au même endroit que fd 3 (stdout). Stderr est maintenant disponible comme stdout et l'ancien stdout est préservé dans stderr. C'est peut-être un peu exagéré mais cela donne plus de détails sur les descripteurs de fichiers de bash (il y en a 9 disponibles pour chaque processus).

131 votes

Une dernière modification serait 3>&- pour fermer le descripteur de rechange que vous avez créé à partir de stdout

2 votes

Peut-on créer un descripteur de fichier qui a stderr et un autre qui a la combinaison de stderr et stdout ? En d'autres termes, est-ce que stderr aller dans deux fichiers différents en même temps ?

0 votes

La commande suivante affiche toujours les erreurs dans la sortie d'état. Qu'est-ce que je manque ? ls -l not_a_file 3>&1 1>&2 2>&3 > errors.txt

268voto

Rich Johnson Points 691

Vous pouvez également rediriger vers un sous-shell

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

Pour le cas qui nous occupe :

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

1 votes

Fonctionne très bien pour la sortie sur l'écran. Avez-vous une idée de la raison pour laquelle le contenu non gravé apparaît à nouveau si je redirige la sortie grep vers un fichier ? Après command 2> >(grep 'something' > grep.log) grep.log contient la même sortie que ungrepped.log de command 2> ungrepped.log

12 votes

Utilisez 2> >(stderr pipe >&2) . Sinon, la sortie du "tube stderr" passera par le "tube stdlog".

0 votes

Ouais ! 2> >(...) fonctionne, j'ai essayé 2>&1 > >(...) mais ce n'est pas le cas

232voto

Pinko Points 857

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

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

...alors tout le stdout est préservé comme stdout et tout le stderr est préservé comme stderr, mais vous ne verrez aucune ligne dans stderr commençant par la chaîne "quelque chose".

Cette méthode a l'avantage unique de ne pas inverser ou jeter stout et stderr, ni de les fusionner, ni d'utiliser des fichiers temporaires.

0 votes

N'est-ce pas ? command 2> >(grep -v something) (sans 1>&2 ) sont les mêmes ?

14 votes

Non, sans cela, le stderr filtré finit par être routé vers stdout.

1 votes

C'est ce dont j'avais besoin - tar sort toujours le message "file changed as we read it" pour un répertoire, donc je veux juste filtrer cette ligne mais voir si d'autres erreurs se produisent. Donc tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2) devrait fonctionner.

120voto

Michael Martinez Points 580

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

Lorsqu'un tuyau ou "|" est présent sur la ligne de commande, la première chose qui se produit est que bash crée un fifo et fait pointer le FD 1 de la commande de gauche vers ce fifo, et fait pointer le FD 0 de la commande de droite vers 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 le descripteur est dupliqué. Ceci est important car, puisque le tube a été configuré en premier, les FD1 (côté gauche) et FD0 (côté droit) sont déjà modifiés par rapport à 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éé. "command FD1" est pointé sur ce tuyau. "grep FD0" est également pointé vers ce tube.
  2. "La commande FD2 est dirigée vers l'endroit où pointe actuellement la commande FD1 (le tuyau).
  3. "commande FD1" pointe vers /dev/null

Ainsi, toute la sortie que "command" écrit dans son FD 2 (stderr) se retrouve dans le tuyau et est lue par "grep" de l'autre côté. Toute la sortie que "command" écrit dans son FD 1 (stdout) se retrouve 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 "command FD 1" et "grep FD 0" y sont pointés
  2. "command FD 1" est pointé vers /dev/null
  3. "commande FD 2" est pointée là où FD 1 pointe actuellement (/dev/null)

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

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

Une dernière note. Le fait qu'un programme écrive quelque chose dans FD1 ou FD2 dépend entièrement du programmeur. Une bonne pratique de programmation dicte que les messages d'erreur doivent aller dans le FD 2 et la sortie normale dans le FD 1, mais vous trouverez souvent une programmation bâclée qui mélange les deux ou ignore la convention.

7 votes

Très bonne réponse. Ma seule suggestion serait de remplacer votre première utilisation de "fifo" par "fifo (a named pipe)". J'utilise Linux depuis un certain temps mais je n'ai jamais réussi à apprendre que c'est un autre terme pour named pipe. Cela m'aurait évité de le chercher, mais je n'aurais pas appris les autres choses que j'ai vues en découvrant cela !

5 votes

@MarkEdington Veuillez noter que FIFO n'est qu'un autre terme pour "named pipe". dans le contexte des tuyaux et de l'IPC . Dans un contexte plus général, FIFO signifie First in, first out, qui décrit l'insertion et le retrait d'une structure de données en file d'attente.

7 votes

@Loomchild Bien sûr. Le point de mon commentaire était que même en tant que développeur chevronné, je n'avais jamais vu FIFO utilisé comme un outil de gestion de la qualité. synonyme pour un tuyau nommé. En d'autres termes, je ne le savais pas : fr.wikipedia.org/wiki/FIFO_(computing_and_electronics)#Pipes - Clarifier cela dans la réponse m'aurait fait gagner du temps.

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