Pourquoi la sortie de certains programmes Linux ne va-t-elle ni à STDOUT ni à STDERR?

21

Pourquoi la sortie de certains programmes Linux ne va-t-elle ni à STDOUT ni à STDERR?

En fait, je veux savoir comment capturer de manière fiable toutes les sorties de programme, quel que soit le «flux» qu'il utilise. Le problème que j'ai, c'est que certains programmes ne semblent pas permettre de capturer leur sortie.

Un exemple est la commande «time»:

time sleep 1 2>&1 > /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

ou

time sleep 1 &> /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

Pourquoi est-ce que je vois la sortie les deux fois? Je m'attendais à ce que tout soit canalisé dans / dev / null .

Quel flux de sortie le temps utilise-t-il et comment le canaliser dans un fichier?

Une façon de contourner le problème consiste à créer un script Bash , par exemple, combine.shcontenant cette commande:

$@ 2>&1

Ensuite, la sortie du «temps» peut être capturée de la bonne manière:

combine.sh time sleep 1 &> /dev/null

(aucune sortie n'est vue - correcte)

Existe-t-il un moyen de réaliser ce que je veux sans utiliser un script de combinaison distinct?

Will Sheppard
la source
3
vous devez d'abord inverser l'ordre: 2>&1 > /dev/nullsignifie que "2 va maintenant à l'endroit où va 1 (c'est-à-dire, le terminal, par défaut), puis 1 va maintenant à / dev / null (mais 2 va toujours au terminal!). utiliser >/dev/null 2>&1pour dire "1 va maintenant à / dev / null, puis 2 va là où 1 va (c'est-à-dire aussi à / dev / null). Cela ne fonctionnera toujours pas ici car le temps intégré ne sera pas redirigé, mais est plus généralement correct (par exemple, cela fonctionnerait si vous utilisez / usr / bin / time). Pensez à "2> & 1" comme copiant la "direction" de 1 en 2, pas comme 2 allant à 1
Olivier Dulac

Réponses:

38

Cette question est traitée dans BashFAQ / 032 . Dans votre exemple, vous devez:

{ time sleep 1; } 2> /dev/null

La raison pour laquelle

time sleep 1 2>/dev/null

ne se comporte pas comme vous l'attendez, car avec cette syntaxe, vous voudrez timela commande sleep 1 2>/dev/null(oui, la commande sleep 1avec stderr redirigée vers /dev/null). La timefonction intégrée fonctionne de cette façon afin de rendre cela possible.

Le bash builtin peut réellement faire cela parce que ... eh bien, c'est un builtin. Un tel comportement serait impossible avec la commande externe timegénéralement située dans /usr/bin. En effet:

$ /usr/bin/time sleep 1 2>/dev/null
$

Maintenant, la réponse à votre question

Pourquoi la sortie de certains programmes Linux ne va-t-elle ni à STDOUT ni à STDERR?

est: il le fait, la sortie passe à stdout ou stderr .

J'espère que cela t'aides!

gniourf_gniourf
la source
2
vous pouvez créer d' autres fd et ont des commandes aller à ceux explicitement (ex: dans le script bash: exec 3>/some/file ; ls >&3 ;)
Olivier Dulac
@OlivierDulac Bien sûr, ou encore plus simple avec le coprocbuiltin. Mais ce n'est pas le cas pour le timebuiltin.
gniourf_gniourf
@ gniourf-gniourf: Je commentais à cause de votre phrase "la sortie va vers stdout ou stderr" ^^
Olivier Dulac
14

Votre question particulière au sujet timebuiltin a répondu, mais il sont des commandes qui n'écrivent pas non plus à stdoutou stderr. Un exemple classique est la commande Unix crypt. cryptsans argument crypte l'entrée standard stdinet l'écrit dans la sortie standard stdout. Il invite l'utilisateur à saisir un mot de passe à l'aide getpass()duquel, par défaut, une invite s'affiche /dev/tty. /dev/ttyest le terminal actuel. L'écriture dans /dev/ttya pour effet d'écrire sur le terminal actuel (s'il y en a un, voir isatty()).

La raison pour laquelle il cryptest impossible d'écrire, stdoutc'est parce qu'il écrit une sortie chiffrée dans stdout. En outre, il est préférable de demander à /dev/ttyau lieu d'écrire de stderrsorte que si un utilisateur redirige stdoutet stderr, l'invite soit toujours visible. (Pour la même raison, cryptimpossible de lire le mot de passe stdin, car il est utilisé pour lire les données à chiffrer.)

Alok
la source
2
+1. Moins pertinent pour l'OP, mais plus pertinent pour tous ceux qui rencontrent "Pourquoi la sortie de certains programmes Linux ne va-t-elle ni à STDOUT ni à STDERR?" via Google. :-)
ruakh
0

time sleep 1 > /dev/null 2>&1# redirige la sortie de "sleep" sur null. Ensuite, "time" écrit sa propre sortie, sans redirection. C'est comme " time (sleep 1 > /dev/null 2>&1)".

(time sleep 1) > /dev/null 2>&1 # exécute "time sleep 1", puis redirige sa sortie vers null.

[] s

Márcio
la source
-1

Le problème dans votre cas est que la redirection fonctionne d'une autre manière. Tu as écrit

time sleep 1 2>&1 > /dev/null

Cela redirige la sortie standard vers /dev/null, puis redirige l'erreur standard vers la sortie standard.

Pour rediriger toutes les sorties, vous devez écrire

time sleep 1 > /dev/null 2>&1 

Ensuite, l'erreur standard sera redirigée vers la sortie standard et ensuite toutes les sorties standard (contenant l'erreur standard) seront redirigées vers /dev/null.

Uwe Plonus
la source
Cela ne fonctionne pas avec le module intégré bash time. Voir ma réponse pour quelques explications.
gniourf_gniourf
+1 car il s'agit d'une réponse utile à une question similaire. Bien que @Olivier l'explique mieux dans le commentaire de la question ci-dessus.
Will Sheppard du