J'ai un programme qui écrit des informations dans stdout
et stderr
, et je dois passer au grep
travers de ce qui arrive à stderr , sans tenir compte de 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. Existe-t-il des astuces de tuyauterie intelligentes?
command 2| othercommand
. Bash est tellement parfait que le développement a pris fin en 1982, donc nous ne verrons jamais ça en bash, j'ai bien peur.Réponses:
Redirigez d'abord stderr vers stdout - le tuyau; puis redirigez stdout vers
/dev/null
(sans changer où va stderr):Pour les détails de la redirection d'E / S dans toute sa variété, voir le chapitre sur les redirections dans le manuel de référence de Bash.
Notez que la séquence de redirections d'E / S est interprétée de gauche à droite, mais les canaux sont configurés avant l'interprétation des redirections d'E / S. Les descripteurs de fichiers tels que 1 et 2 sont des références à des descriptions de fichiers ouverts. L'opération
2>&1
fait que le descripteur de fichier 2 aka stderr fait référence à la même description de fichier ouverte que le descripteur de fichier 1 aka stdout fait actuellement référence (voirdup2()
etopen()
). L'opération>/dev/null
modifie ensuite le descripteur de fichier 1 pour qu'il fasse référence à une description de fichier ouvert pour/dev/null
, mais cela ne change pas le fait que le descripteur de fichier 2 se réfère à la description de fichier ouvert vers laquelle le descripteur de fichier 1 pointait à l'origine - à savoir, le canal.la source
command 2> /dev/stdout 1> /dev/null | grep 'something'
/dev/stdout
et al, ou utiliser/dev/fd/N
. Ils seront légèrement moins efficaces à moins que la coque ne les traite comme des cas spéciaux; la notation numérique pure n'implique pas l'accès aux fichiers par nom, mais l'utilisation des périphériques signifie une recherche de nom de fichier. Que vous puissiez mesurer cela est discutable. J'aime la brièveté de la notation numérique - mais je l'utilise depuis si longtemps (plus d'un quart de siècle; aïe!) Que je ne suis pas qualifié pour juger de ses mérites dans le monde moderne.2>&1
, ce qui signifie «connecter stderr au descripteur de fichier vers lequel stdout va actuellement ». La deuxième opération consiste à «changer la/dev/null
sortie standard pour qu'elle passe à », en laissant stderr se diriger vers la sortie standard, le tuyau. Le shell divise tout d'abord le symbole du tuyau, donc la redirection du tuyau se produit avant les redirections2>&1
ou>/dev/null
, mais c'est tout; les autres opérations sont de gauche à droite. (De droite à gauche ne fonctionnerait pas.)/dev/null
l'équivalent de Windowsnul
).Ou pour permuter la sortie de l'erreur standard et de la sortie standard, utilisez:
Cela crée un nouveau descripteur de fichier (3) et l'affecte au même endroit que 1 (sortie standard), puis attribue fd 1 (sortie standard) au même endroit que fd 2 (erreur standard) et affecte finalement fd 2 (erreur standard ) au même endroit que fd 3 (sortie standard).
L'erreur standard est désormais disponible en sortie standard et l'ancienne sortie standard est conservée dans l'erreur standard. Cela peut être exagéré, mais cela donne, espérons-le, plus de détails sur les descripteurs de fichiers Bash (neuf sont disponibles pour chaque processus).
la source
3>&-
de fermer le descripteur de rechange que vous avez créé à partir de stdoutstderr
et un autre qui a la combinaison destderr
etstdout
? En d'autres termes, peutstderr
- on accéder à deux fichiers différents à la fois?Dans Bash, vous pouvez également rediriger vers un sous-shell en utilisant la substitution de processus :
Pour le cas en question:
la source
command 2> >(grep 'something' > grep.log)
grep.log contienne la même sortie que ungrepped.log decommand 2> ungrepped.log
2> >(stderr pipe >&2)
. Sinon, la sortie du "stderr pipe" passera par le "stdlog pipe".2> >(...)
,2>&1 > >(...)
ça marche, j'ai essayé mais ça n'a pas marchéawk -f /new_lines.awk <in-content.txt > out-content.txt 2> >(tee new_lines.log 1>&2 )
Dans ce cas, je voulais également voir ce qui sortait comme des erreurs sur ma console. Mais STDOUT allait vers le fichier de sortie. Donc, à l'intérieur du sous-shell, vous devez rediriger ce STDOUT vers STDERR à l'intérieur des parenthèses. Pendant que cela fonctionne, la sortie STDOUT de latee
commande se termine à la fin duout-content.txt
fichier. Cela me semble incohérent.2>&1 1> >(dest pipe)
En combinant la meilleure 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 "quelque chose".
Cela a l'avantage unique de ne pas inverser ou supprimer stdout et stderr, ni de les mélanger ensemble, ni d'utiliser de fichiers temporaires.
la source
command 2> >(grep -v something)
(sans1>&2
) la même chose?tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2)
devrait donc fonctionner.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 canaux dans bash font une chose: modifier où les descripteurs de fichiers de processus 0, 1 et 2 pointent (voir / proc / [pid] / fd / *).
Quand une 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 de gauche sur ce fifo, et pointe le FD 0 de la commande de droite sur 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 car depuis que le tuyau a été installé en premier, le 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 ceci:
Voici ce qui se passe, dans l'ordre:
Ainsi, toutes les sorties que "command" écrit sur son FD 2 (stderr) se dirigent vers le tuyau et sont lues par "grep" de l'autre côté. Toutes les sorties que la "commande" écrit dans son FD 1 (stdout) se dirigent vers / dev / null.
Si à la place, vous exécutez ce qui suit:
Voici ce qui se passe:
Ainsi, tous les stdout et stderr de la "commande" vont dans / dev / null. Rien ne va dans le tuyau, et donc "grep" se fermera sans afficher quoi que ce soit à l'écran.
Notez également que les redirections (descripteurs de fichiers) peuvent être en lecture seule (<), en écriture seule (>) ou en lecture-écriture (<>).
Une note finale. Qu'un programme écrive quelque chose sur FD1 ou FD2, cela 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 bâclée qui mélange les deux ou ignore la convention.
la source
Si vous utilisez Bash, utilisez:
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
la source
|&
est égal à2>&1
qui combine stdout et stderr. La question demandait explicitement une sortie sans sortie standard.>/dev/null |&
développez>/dev/null 2>&1 |
et signifie que l'inode stdout est vide dans le tuyau car personne (# 1 # 2 à la fois lié à / dev / null inode) n'est lié à l'inode stdout (par exemplels -R /tmp/* >/dev/null 2>&1 | grep i
, donnera vide, maisls -R /tmp/* 2>&1 >/dev/null | grep i
laissera # 2 qui est lié à l'inode standard sortira).( echo out; echo err >&2 ) >/dev/null |& grep "."
ne donne aucune sortie (là où on veut "errer").man bash
indique que si | & est utilisé… est un raccourci pour 2> & 1 |. Cette redirection implicite de l'erreur standard vers la sortie standard est effectuée après toutes les redirections spécifiées par la commande. Donc, nous redirigeons d'abord le FD1 de la commande vers null, puis nous redirigeons le FD2 de la commande vers FD1, c'est-à-dire. null, donc le FD0 de grep ne reçoit aucune entrée. Voir stackoverflow.com/a/18342079/69663 pour une explication plus approfondie.Pour ceux qui veulent rediriger stdout et stderr en permanence vers des fichiers, grep sur stderr, mais gardez la stdout pour écrire des messages sur un tty:
la source
Cela redirigera command1 stderr vers command2 stdin, tout en laissant command1 stdout tel quel.
Extrait du LDP
la source
Je viens de trouver une solution pour envoyer
stdout
à une commande etstderr
à une autre, en utilisant des canaux nommés.Voici.
C'est probablement une bonne idée de supprimer les tuyaux nommés par la suite.
la source
Vous pouvez utiliser le shell rc .
Installez d'abord le package (c'est moins de 1 Mo).
Voici un exemple de la façon dont vous pouvez ignorer la sortie standard et l'erreur standard de canal vers grep dans
rc
:Vous pouvez le faire sans quitter Bash:
Comme vous l'avez peut-être remarqué, vous pouvez spécifier le descripteur de fichier que vous souhaitez canaliser en utilisant des crochets après le tube.
Les descripteurs de fichiers standard sont numérotés comme suit:
la source
J'essaie de suivre, je trouve que ça marche aussi,
la source