web-dev-qa-db-fra.com

Comment puis-je rediriger STDERR vers STDOUT, mais ignorer le STDOUT d'origine?

J'ai un programme dont la sortie de STDERR je veux inspecter et exécuter grep sur etc.

Je pouvais donc le rediriger vers STDOUT et utiliser grep, mais le problème est que je pas veux le contenu STDOUT d'origine.

Donc, celui-ci ne fera pas

cmd 2>&1 | grep pattern

car il mélangera le STDOUT et le STDERR d'origine.

Et celui-ci ne fonctionne pas car grep ne lit pas la sortie STDERR:

cmd 1>/dev/null | grep pattern

Mais aussi, celui-ci ne fonctionnera pas:

cmd 1>/dev/null 2>&1 | grep pattern

car la sortie sera complètement vide, car tout est écrit dans /dev/null.

Mais il doit y avoir un moyen simple de le faire?

57
Frank

Ce qui ne fonctionne pas:

La raison pour laquelle la dernière commande que vous avez citée:

cmd 1>/dev/null 2>&1 | grep pattern

ne fonctionne pas, découle d'une confusion sur l'ordre dans lequel la redirection fonctionne. Vous vous attendiez à ce que la dernière redirection citée soit appliquée à celles qui le précèdent sur chaque sortie, de sorte que la sortie du descripteur de fichier de sortie standard d'origine (1) ira vers/dev/null, et la sortie vers le descripteur de fichier d'erreur standard (2) sera aller à la sortie standard d'origine.

Cependant, ce n'est pas ainsi que fonctionne la redirection Shell. Chaque redirection entraîne le "remappage" des descripteurs de fichiers en fermant la "source" et en dupliquant la "destination" (voir les pages man de dup(2) et close(2)), en ordre. Cela signifie que dans votre commande, la sortie standard est d'abord remplacée par /dev/null, Puis l'erreur standard est remplacée par la sortie standard, qui est déjà /dev/null.

Ce qui fonctionne:

Par conséquent, pour obtenir l'effet souhaité, il vous suffit d'inverser les redirections. Ensuite, vous aurez l'erreur standard aller à la sortie standard, et la sortie standard d'origine aller à /dev/null:

cmd 2>&1 >/dev/null | grep pattern

(notez que 1 avant > n'est pas nécessaire - pour la redirection de sortie, la sortie standard est la valeur par défaut)


Addendum : Charlie a mentionné la redirection vers &- Pour fermer un descripteur de fichier. Si vous utilisez un shell interactif qui prend en charge cette extension (bash et certaines autres implémentations le font mais pas toutes et c'est non standard ), vous pouvez également le faire comme ceci:

cmd 2>&1 >&- | grep pattern

Cela peut être mieux - cela peut gagner du temps, car lorsque la commande essaie d'écrire sur la sortie standard, l'appel à write peut échouer immédiatement sans attendre un changement de contexte dans le noyau et le pilote gérant /dev/null (selon l'implémentation de l'appel système - certains peuvent intercepter cela dans la fonction libc, et certains peuvent également avoir une gestion spéciale pour /dev/null). S'il y a beaucoup de sorties qui peuvent valoir la peine, et c'est plus rapide à taper.

Cela fonctionnera principalement parce que la plupart des programmes ne se soucient pas s'ils n'écrivent pas sur la sortie standard (qui vérifie vraiment la valeur de retour de printf?) Et ne se soucieront pas que la sortie standard soit fermée. Mais certains programmes peuvent renflouer avec un code d'échec si write échoue - bloquent généralement les processeurs, les programmes utilisant une bibliothèque soignée pour les E/S ou se connectant à la sortie standard. Donc, si cela ne fonctionne pas, souvenez-vous que c'est une cause probable et essayez /dev/null.

101
Tom Alsberg

Fermez d'abord STDOUT:

1>&-, >&-

Voir ici .

3
Charlie Martin