Comment savoir si le résultat d'une commande ou d'un script shell est stdout ou stderr

32

Supposons que je lance une commande ou un script shell et qu'il me donne une sortie. Sans connaître les éléments internes de cette commande ou de ce script shell, comment déterminer si la sortie provient de stderrou stdout?

Pour, par exemple,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

contre

ls -ld /test
ls: /test: No such file or directory

Comment puis-je m'assurer que la première commande est imprimée stdoutet la seconde stderr(l'a-t-elle fait?)?

KM.
la source
1
Quel problème essayez-vous de résoudre ici?
Kenster
3
A eu peur que quelqu'un demande cela; aucun vraiment, surtout curieux et espérant améliorer ma compréhension de la redirection.
KM.
7
Vous pouvez mettre stderreddans votre environnement shell LD_PRELOADpour obtenir stdoutet stderrdans différentes couleurs. Voici une question connexe dans la même veine.
Anko

Réponses:

18

Il n'y a aucun moyen de savoir une fois que la sortie a déjà été imprimée. Dans ce cas, les deux stdoutet stderrsont connectés au terminal, les informations sur le flux qui a été écrit ont déjà été perdues au moment où le texte est apparu sur votre terminal; ils ont été combinés par le programme avant même d'arriver au terminal.

Ce que vous pouvez faire, dans un cas comme celui ci-dessus, serait d’exécuter la commande avec stdoutet stderrredirigé vers différents endroits et de voir ce qui se passe. Ou exécutez-le deux fois, une fois avec stdoutredirigé vers /dev/nullet une fois avec stderrredirigé vers /dev/null, et voyez lequel de ces cas entraîne l'affichage du texte.

Vous pouvez rediriger stdoutvers /dev/nullen cliquant >/dev/nullsur à la fin de la ligne de commande et vous pouvez également rediriger stderrvers /dev/nullen ajoutant 2>/dev/null.

godlygeek
la source
9

Vous pouvez rediriger stdout en utilisant > fileet rediriger en utilisant stderr 2> file. De nombreux shells modernes supportent la redirection vers les commandes, vous pouvez donc utiliser sedpour mettre en évidence quelle sortie provient de quel flux:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory
Mark Plotnick
la source
Très agréable! Ce serait formidable de pouvoir surligner les lignes en couleurs plutôt que préfixes.
dotancohen
3
@dancoo: On peut! Par exemple,(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
2
Notez que s'il y a une sortie mixte de stdout et stderr, stdout sera d'abord imprimé, puis stderr.
nyuszika7h
5

Le annotate-outputscript de Debian devscriptsvous permet de le faire de manière sélective:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

La deuxième colonne indique stdout et stderr avec Oet Erespectivement.

Il y a quelques mises en garde, la principale étant comme indiqué dans les autres réponses: vous ne pouvez pas le faire après coup. Ni le shell ni le terminal ne savent comment un programme arbitraire utilise ses descripteurs de fichier, bien que le shell soit responsable de leur configuration initiale.

Cette méthode utilise fifos, l'écriture sur un fifo peut se comporter différemment de l'écriture sur un tty, et écrire sur deux fifos différents est nettement différent (problèmes de synchronisation / d'entrelacement potentiels). En outre, il ne convient pas à une utilisation interactive, par exemple, ce annotate-output bashn'est pas un bon plan, mais il est utile à de nombreuses autres fins. Il existe de très nombreux exemples de scripts et de fonctions shell répondant aux questions connexes sur la colorisation de stdin / stdout / stderr. Le plus robuste est stderrd, qui utilise la modification à l'exécution (la plupart) des programmes pour modifier les données écrites sur stderr.

Cette question à laquelle Anko se réfère a de bonnes réponses sur ce thème: coloriser la sortie stdout / stderr: Puis-je configurer mon shell pour imprimer STDERR et STDOUT dans des couleurs différentes?

mr.spuratic
la source
1
Notez qu'il s'agit d'un bashscript utilisant des while readboucles et exécutant une datecommande pour chaque ligne de stdout ou stderr, de sorte qu'il sera beaucoup moins efficace que son cmd > >(ts '%T O:') 2> >(ts '%T E:')équivalent.
Stéphane Chazelas
1

Outre les autres réponses, il est intéressant de souligner /proc/$PID/fd(bien que cela ne réponde pas à la question):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

Comme vous le voyez, vous pouvez voir ici les descripteurs de fichier ouverts pour un processus. 0est le STDIN, 1est le STDOUTet 2est le STDERR. Si vous ne redirigiez pas STDOUT ou STDERR, vous verriez /dev/pts/33(dans cet exemple au moins) car ils pointeraient vers le terminal.

notes : /proc/$PIDexiste uniquement pour les processus en cours d'exécution. Dans ce cas, j’ai utilisé catsans arguments afin que cela ne se termine pas avant la fermeture du fichier STDIN. Je l'ai également exécuté en arrière-plan, de sorte que j'ai le PID immédiatement pour cet exemple.

Carlos Campderrós
la source
0

Ce que vous demandez n'est pas tout à fait clair, mais cela pourrait aider

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

La source

Si le code de sortie est 0 cela signifie simplement que la commande est exécutée correctement (stdout), ici vous pouvez trouver des significations si le code de sortie est différent de 0 (stderr)

Klerk
la source
Très intéressant! Je n'aurais jamais connecté les statuts de sortie à la redirection. Est-ce que zéro implique stdoutet non-zéro implique stderr?
KM.
7
@KM., No. Je dirais que cela est fortement corrélé, mais rien n'empêche un programme d'écrire stderret de retourner un bon code d'erreur, ou d'écrire stdoutet de retourner un mauvais code d'erreur. En fait, essayez find /root- en supposant que vous n’exécutez pas en tant que root, vous devriez obtenir 2 lignes imprimées - "/ root" est imprimé sur stdout, et "find: / root: Autorisation refusée" est imprimé sur stderr. Et find renvoie un mauvais code de retour.
godlygeek
Le problème de op est clair: comment savoir lequel est stdout ou stderr.
it_is_a_literature
0

STDERR aura généralement le nom du programme ajouté au message avec deux points.

Exemple:

rpm -zq some_utils 
rpm: -zq: unknown option

Contre

rpm -ql some_utils 
package some_utils is not installed
papou
la source
-1

Pour capturer et tester la sortie d'erreur:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
mlgoth
la source