Que sont stdin, stdout et stderr sous Linux?

stdin, stdout et stderr sont trois flux de données créés lorsque vous lancez une commande Linux. Vous pouvez les utiliser pour savoir si vos scripts sont envoyés ou redirigés. Nous vous montrons comment.

Les flux rejoignent deux points

Dès que vous commencez à en apprendre davantage sur les systèmes d’exploitation Linux et Unix, vous rencontrerez les termes stdin, stdout et stederr. Ceux-ci sont trois flux standard qui sont établis lorsqu’une commande Linux est exécutée. En informatique, un flux est quelque chose qui peut transférer des données. Dans le cas de ces flux, ces données sont du texte.

Les flux de données, comme les flux d’eau, ont deux extrémités. Ils ont une source et une sortie. La commande Linux que vous utilisez fournit une extrémité de chaque flux. L’autre extrémité est déterminée par le shell qui a lancé la commande. Cette extrémité sera connectée à la fenêtre du terminal, connectée à un tube ou redirigée vers un fichier ou une autre commande, selon la ligne de commande qui a lancé la commande.

Les flux standard Linux

Sous Linux, stdin est le flux d’entrée standard. Cela accepte le texte comme entrée. La sortie texte de la commande vers le shell est fournie via le flux stdout (sortie standard). Les messages d’erreur de la commande sont envoyés via le flux stderr (erreur standard).

Vous pouvez donc voir qu’il existe deux flux de sortie, stdout et stderr, et un flux d’entrée, stdin. Étant donné que les messages d’erreur et la sortie normale ont chacun leur propre conduit pour les transporter vers la fenêtre du terminal, ils peuvent être traités indépendamment les uns des autres.

Les flux sont traités comme des fichiers

Les flux sous Linux – comme presque tout le reste – sont traités comme s’il s’agissait de fichiers. Vous pouvez lire du texte à partir d’un fichier et écrire du texte dans un fichier. Ces deux actions impliquent un flux de données. Le concept de gestion d’un flux de données sous forme de fichier n’est donc pas si compliqué.

Chaque fichier associé à un processus se voit attribuer un numéro unique pour l’identifier. C’est ce qu’on appelle le descripteur de fichier. Chaque fois qu’une action doit être effectuée sur un fichier, le descripteur de fichier est utilisé pour identifier le fichier.

Ces valeurs sont toujours utilisées pour stdin, stdout et stderr:

0: stdin
1: sortie standard
2: stderr

Réagir aux tuyaux et aux redirections

Pour faciliter l’introduction d’un sujet à quelqu’un, une technique courante consiste à enseigner une version simplifiée du sujet. Par exemple, avec la grammaire, on nous dit que la règle est « I avant E, sauf après C. » Mais en fait, là sont plus d’exceptions à cette règle qu’il y a des cas qui y obéissent.

  Comment (et pourquoi) exécuter des versions portables de Windows

Dans la même veine, quand on parle de stdin, stdout et stderr, il est pratique de trotter l’axiome accepté selon lequel un processus ne sait ni ne se soucie de l’endroit où ses trois flux standard se terminent. Un processus doit-il se soucier de savoir si sa sortie va au terminal ou est redirigée dans un fichier? Peut-il même dire si son entrée provient du clavier ou y est acheminée par un autre processus?

En fait, un processus le sait – ou du moins il peut le découvrir s’il choisit de vérifier – et il peut modifier son comportement en conséquence si l’auteur du logiciel a décidé d’ajouter cette fonctionnalité.

On voit très facilement ce changement de comportement. Essayez ces deux commandes:

ls

ls dans une fenêtre de terminal

ls | cat

Sortie ls dans une fenêtre de terminal

La commande ls se comporte différemment si sa sortie (stdout) est redirigée vers une autre commande. C’est ls qui bascule sur une sortie de colonne unique, ce n’est pas une conversion effectuée par cat. Et ls fait la même chose si sa sortie est redirigée:

ls > capture.txt

ls> capture.txt dans une fenêtre de terminal ”width =” 646 ″ height = ”57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ” onerror = ”this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p><pre> capture de chat.txt </pre><p> <img loading =

Redirection de stdout et stderr

Il y a un avantage à avoir des messages d’erreur envoyés par un flux dédié. Cela signifie que nous pouvons rediriger la sortie d’une commande (stdout) vers un fichier et toujours voir les messages d’erreur (stderr) dans la fenêtre du terminal. Vous pouvez réagir aux erreurs si nécessaire, au fur et à mesure qu’elles se produisent. Cela empêche également les messages d’erreur de contaminer le fichier vers lequel stdout a été redirigé.

Tapez le texte suivant dans un éditeur et enregistrez-le dans un fichier appelé error.sh.

#!/bin/bash

echo "About to try to access a file that doesn't exist"
cat bad-filename.txt

Rendez le script exécutable avec cette commande:

chmod +x error.sh

La première ligne du script fait écho au texte dans la fenêtre du terminal, via le flux stdout. La deuxième ligne tente d’accéder à un fichier qui n’existe pas. Cela générera un message d’erreur qui est livré via stderr.

Exécutez le script avec cette commande:

./error.sh

./error.sh dans une fenêtre de terminal

Nous pouvons voir que les deux flux de sortie, stdout et stderr, ont été affichés dans les fenêtres du terminal.

sortie du script error.sh dans une fenêtre de terminal

Essayons de rediriger la sortie vers un fichier:

./error.sh > capture.txt

./error.sh> capture.txt dans une fenêtre de terminal ”width =” 646 ″ height = ”57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ” onerror = ”this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p><p> Le message d’erreur qui est livré via stderr est toujours envoyé à la fenêtre du terminal. Nous pouvons vérifier le contenu du fichier pour voir si la sortie stdout est allée au fichier. </p><pre> cat capture.txt </pre><p> <img loading =

La sortie de stdin a été redirigée vers le fichier comme prévu.

contenu de capture.txt dans une fenêtre de terminal

Le symbole de redirection> fonctionne avec stdout par défaut. Vous pouvez utiliser l’un des descripteurs de fichier numériques pour indiquer le flux de sortie standard que vous souhaitez rediriger.

  Comment installer le thème d'icônes Antu sur Linux

Pour rediriger explicitement stdout, utilisez cette instruction de redirection:

1>

Pour rediriger explicitement stderr, utilisez cette instruction de redirection:

2>

Essayons à nouveau notre test, et cette fois nous utiliserons 2>:

./error.sh 2> capture.txt

./error.sh 2> capture.txt dans une fenêtre de terminal ”width =” 646 ″ height = ”57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ” onerror = ”this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p><p> Le message d’erreur est redirigé et le message d’écho stdout est envoyé à la fenêtre du terminal: </p><p > <classe img =

Le message stderr est dans capture.txt comme prévu.

contenu du fichier capture.txt dans une fenêtre de terminal

Redirection à la fois stdout et stderr

Sûrement, si nous pouvons rediriger stdout ou stderr vers un fichier indépendamment l’un de l’autre, nous devrions être en mesure de les rediriger tous les deux en même temps, vers deux fichiers différents?

Oui nous pouvons. Cette commande dirigera stdout vers un fichier appelé capture.txt et stderr vers un fichier appelé error.txt.

./error.sh 1> capture.txt 2> error.txt

./error.sh 1> capture.txt 2> error.txt dans une fenêtre de terminal ”width =” 646 ″ height = ”57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ” onerror = ”this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p><p> Étant donné que les deux flux de sortie – sortie standard et erreur standard – sont redirigés vers des fichiers, il n’y a pas de sortie visible dans la fenêtre du terminal. Nous retournons à l’invite de ligne de commande comme si rien ne s’était passé. </p><p> <img loading =

Vérifions le contenu de chaque fichier:

cat capture.txt
cat error.txt

contenu de capture.txt et error.txt dans une fenêtre de terminal

Redirection de stdout et stderr vers le même fichier

C’est bien, nous avons chacun des flux de sortie standard vers son propre fichier dédié. La seule autre combinaison que nous pouvons faire est d’envoyer à la fois stdout et stderr dans le même fichier.

Nous pouvons y parvenir avec la commande suivante:

./error.sh > capture.txt 2>&1

Décomposons cela.

./error.sh: lance le fichier de script error.sh.
> capture.txt: redirige le flux stdout vers le fichier capture.txt. > est un raccourci pour 1>.
2> & 1: Ceci utilise l’instruction de redirection &>. Cette instruction vous permet de dire au shell de faire en sorte qu’un flux arrive à la même destination qu’un autre flux. Dans ce cas, nous disons « rediriger le flux 2, stderr, vers la même destination vers laquelle le flux 1, stdout, est redirigé. »

./error.sh> capture.txt 2 &> 1 dans une fenêtre de terminal ”width =” 646 ″ height = ”57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ” onerror = ”this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p><p> Il n’y a pas de sortie visible. C’est encourageant. </p><p> <img loading =

Vérifions le fichier capture.txt et voyons ce qu’il contient.

cat capture.txt

contenu de capture.txt dans une fenêtre de terminal

Les flux stdout et stderr ont été redirigés vers un seul fichier de destination.

Pour que la sortie d’un flux soit redirigée et supprimée silencieusement, dirigez la sortie vers / dev / null.

Détection de la redirection dans un script

Nous avons expliqué comment une commande peut détecter si l’un des flux est redirigé et peut choisir de modifier son comportement en conséquence. Pouvons-nous accomplir cela dans nos propres scripts? Oui nous pouvons. Et c’est une technique très facile à comprendre et à utiliser.

Tapez le texte suivant dans un éditeur et enregistrez-le sous input.sh.

#!/bin/bash

if [ -t 0 ]; then

  echo stdin coming from keyboard
 
else

  echo stdin coming from a pipe or a file
 
fi

Utilisez la commande suivante pour le rendre exécutable:

chmod +x input.sh

La partie intelligente est la test entre crochets. L’option -t (terminal) renvoie true (0) si le fichier associé au descripteur de fichier se termine dans la fenêtre du terminal. Nous avons utilisé le descripteur de fichier 0 comme argument du test, qui représente stdin.

  Comment exécuter une application en tant qu'administrateur au démarrage sur Windows 10

Si stdin est connecté à une fenêtre de terminal, le test s’avérera vrai. Si stdin est connecté à un fichier ou à un tube, le test échouera.

Nous pouvons utiliser n’importe quel fichier texte pratique pour générer une entrée dans le script. Ici, nous en utilisons un appelé dummy.txt.

./input.sh 

./input.sh <dummy.txt dans une fenêtre de terminal

The output shows that the script recognizes that the input isn’t coming from a keyboard, it is coming from a file. If you chose to, you could vary your script’s behavior accordingly.

sortie du script dans une fenêtre de terminal

C'était avec une redirection de fichier, essayons-le avec un tube.

chat dummy.txt |  ./input.sh

chat dummy.txt | ./input.sh dans une fenêtre de terminal

Le script reconnaît que son entrée y est envoyée. Ou plus précisément, il reconnaît une fois de plus que le flux stdin n'est pas connecté à une fenêtre de terminal.

sortie du script dans une fenêtre de terminal

Exécutons le script sans tubes ni redirections.

./input.sh

./input.sh dans une fenêtre de terminal

Le flux stdin est connecté à la fenêtre du terminal et le script le signale en conséquence.

Pour vérifier la même chose avec le flux de sortie, nous avons besoin d'un nouveau script. Tapez ce qui suit dans un éditeur et enregistrez-le sous output.sh.

#!/bin/bash

if [ -t 1 ]; then

echo stdout is going to the terminal window
 
else

echo stdout is being redirected or piped
 
fi

Utilisez la commande suivante pour le rendre exécutable:

chmod +x input.sh

Le seul changement significatif à ce script est dans le test entre crochets. Nous utilisons le chiffre 1 pour représenter le descripteur de fichier pour stdout.

Essayons-le. Nous allons diriger la sortie via cat.

./output | cat

./output | chat dans une fenêtre de terminal

Le script reconnaît que sa sortie ne va pas directement à une fenêtre de terminal.

sortie de script dans une fenêtre de terminal

Nous pouvons également tester le script en redirigeant la sortie vers un fichier.

./output.sh > capture.txt

./output.sh> capture.txt dans une fenêtre de terminal

Il n'y a pas de sortie dans la fenêtre du terminal, nous retournons silencieusement à l'invite de commande. Comme on pouvait s'y attendre.

sortie de script dans une fenêtre de terminal

Nous pouvons regarder à l'intérieur du fichier capture.txt pour voir ce qui a été capturé. Utilisez la commande suivante pour ce faire.

cat capture.sh

cat capture.sh dans une fenêtre de terminal

Encore une fois, le simple test de notre script détecte que le flux stdout n'est pas envoyé directement à une fenêtre de terminal.

Si nous exécutons le script sans tubes ni redirections, il devrait détecter que stdout est livré directement dans la fenêtre du terminal.

./output.sh

./output.sh dans une fenêtre de terminal

Et c'est exactement ce que nous voyons.

sortie de script dans une fenêtre de terminal

Flux de conscience

Savoir savoir si vos scripts sont connectés à la fenêtre du terminal, ou à un tube, ou sont en cours de redirection, vous permet d'ajuster leur comportement en conséquence.

La journalisation et la sortie de diagnostic peuvent être plus ou moins détaillées, selon qu'elles vont à l'écran ou à un fichier. Les messages d'erreur peuvent être enregistrés dans un fichier différent de la sortie normale du programme.

Comme c'est généralement le cas, plus de connaissances apporte plus d'options.