103.4 Leçon 1
Certification : |
LPIC-1 (101) |
---|---|
Version : |
5.0 |
Thème : |
103 Commandes GNU et Unix |
Objectif : |
103.4 Utiliser les flux, les tubes et les redirections |
Leçon : |
1 sur 2 |
Introduction
Tous les programmes informatiques reposent sur le même principe de base : les données fournies par une source quelconque sont transformées pour produire un résultat intelligible. Dans le contexte du shell Linux, la source de données peut être un fichier local, un fichier distant, un périphérique (comme un clavier), etc. La sortie du programme est généralement affichée sur un écran, mais il est tout aussi courant de stocker les données de sortie dans un système de fichiers local, de les envoyer vers un périphérique distant, de les diffuser via des haut-parleurs, etc.
Les systèmes d’exploitation de type Unix comme Linux offrent une grande variété de méthodes d’entrée/sortie. En l’occurrence, la méthode des descripteurs de fichiers permet d’associer dynamiquement des nombres entiers à des canaux de données, de sorte qu’un processus puisse les référencer comme ses flux de données d’entrée/sortie.
Les processus Linux standards disposent de trois canaux de communication ouverts par défaut : le canal entrée standard ou standard input (le plus souvent simplement appelé stdin
), le canal sortie standard ou standard output (stdout
) et le canal sortie d’erreur standard ou standard error (stderr
). Les descripteurs de fichiers numériques respectifs assignés à ces canaux sont 0
à stdin
, 1
à stdout
et 2
à stderr
. Les canaux de communication sont également accessibles par le biais des périphériques spéciaux /dev/stdin
, /dev/stdout
et /dev/stderr
.
Ces trois canaux de communication standards permettent aux programmeurs d’écrire du code qui lit et écrit des données sans se soucier du média dont elles proviennent ou auquel elles sont destinées. Par exemple, si un programme a besoin d’un jeu de données en entrée, il peut simplement demander des données à l’entrée standard et le dispositif qui fait office d’entrée standard fournira ces données. De même, la méthode la plus simple qu’un programme puisse utiliser pour afficher ses données de sortie est de les envoyer vers la sortie standard. Dans une session shell standard, le clavier est défini comme l’entrée standard (stdin
) et l’écran du moniteur est défini comme la sortie standard (stdout
) et la sortie d’erreur standard (stderr
).
Le shell Bash permet de réaffecter les canaux de communication lors du chargement d’un programme. Il permet, par exemple, de ne pas utiliser l’écran comme sortie standard et de se servir d’un fichier du système de fichiers local comme stdout
.
Les redirections
La réaffectation du descripteur de fichier d’un canal dans l’environnement shell est appelée une redirection. Une redirection est définie par un caractère spécial dans la ligne de commande. Par exemple, pour rediriger la sortie standard d’un processus vers un fichier, le symbole plus grand que >
est placé à la fin de la commande et suivi du chemin d’accès vers le fichier qui recevra la sortie redirigée :
$ cat /proc/cpuinfo >/tmp/cpu.txt
Par défaut, seul le contenu arrivant sur la sortie standard (stdout
) est redirigé. Cela est dû au fait que la valeur numérique du descripteur de fichier doit normalement être spécifiée juste avant le symbole plus grand que >
et, lorsqu’elle n’est pas spécifiée, Bash redirige la sortie standard. Par conséquent, l’utilisation de >
équivaut à 1>
(la valeur du descripteur de fichier de la sortie standard stdout
est 1
).
Pour capturer le contenu de la sortie d’erreur standard stderr
, on utilisera plutôt la redirection 2>
. La plupart des programmes en ligne de commande envoient des informations de débogage et des messages d’erreur vers le canal d’erreur standard. Il est possible, par exemple, de capturer le message d’erreur déclenché par la tentative de lire un fichier inexistant :
$ cat /proc/cpu_info 2>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory
La sortie standard stdout
et la sortie d’erreur standard stderr
sont toutes les deux redirigées vers la même cible avec &>
ou >&
. Évitez de placer des espaces à côté de l’esperluette &
, faute de quoi Bash va la considérer comme une instruction pour exécuter le processus en arrière-plan au lieu d’effectuer la redirection.
La cible en question sera un chemin d’accès vers un fichier accessible en écriture, comme /tmp/cpu.txt
, ou un descripteur de fichier accessible en écriture. Un descripteur de fichier cible est représenté par une esperluette &
suivie de la valeur numérique du descripteur de fichier. Par exemple, 1>&2
redirige la sortie standard stdout
vers la sortie d’erreur standard stderr
. Pour faire l’inverse et rediriger la sortie d’erreur standard stderr
vers la sortie standard stdout
, il faudra plutôt utiliser 2>&1
.
Même si ce n’est pas très pratique, étant donné qu’il existe un moyen plus efficace d’effectuer la même tâche, il est possible de rediriger stderr
vers stdout
puis de rediriger le tout vers un fichier. Par exemple, une redirection pour écrire à la fois stderr
et stdout
dans un fichier nommé log.txt
peut s’écrire sous la forme >log.txt 2>&1
. Cependant, la principale motivation pour rediriger stderr vers stdout consiste à analyser les messages d’erreur et de débogage. On peut très bien rediriger la sortie standard d’un programme vers l’entrée standard d’un autre programme, mais il n’est pas possible de rediriger directement l’erreur standard vers l’entrée standard d’un autre programme. Ainsi, les messages d’un programme envoyés vers stderr
doivent d’abord être redirigés vers stdout
afin d’être lus par le stdin
d’un autre programme.
Pour ignorer tout simplement la sortie d’une commande, son contenu peut être redirigé vers le fichier spécial /dev/null
. Par exemple, >log.txt 2>/dev/null
enregistre le contenu de stdout
dans le fichier log.txt
en rejetant les erreurs. Le fichier /dev/null
est accessible en écriture à n’importe quel utilisateur, mais aucune donnée ne pourra être récupérée, étant donné qu’elles ne sont stockées nulle part.
Un message d’erreur s’affiche si la cible spécifiée n’est pas accessible en écriture (si le chemin pointe vers un répertoire ou un fichier en lecture seule) et aucune modification n’est apportée à la cible. En revanche, une redirection de sortie écrase une cible existante accessible en écriture sans la moindre confirmation. Les fichiers sont écrasés par les redirections de sortie à moins que l’option Bash noclobber
soit activée, ce qui peut se faire pour la session en cours avec la commande set -o noclobber
ou set -C
:
$ set -o noclobber $ cat /proc/cpu_info 2>/tmp/error.txt -bash: /tmp/error.txt: cannot overwrite existing file
Pour désactiver l’option noclobber
pour la session en cours, il suffit d’invoquer set +o noclobber
ou set +C
. Pour rendre l’option noclobber
persistante, il faut l’inclure dans l’environnement Bash de l’utilisateur ou du système.
Même avec l’option noclobber
activée, il est possible d’ajouter des données redirigées à un contenu existant. Cela peut se faire grâce à une redirection écrite avec un double chevron >>
:
$ cat /proc/cpu_info 2>>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
Dans l’exemple précédent, le nouveau message d’erreur a été ajouté au message existant dans le fichier /tmp/error.txt
. Si le fichier n’existe pas encore, il sera créé avec les nouvelles données.
La source de données de l’entrée standard d’un processus peut également être réaffectée. Le symbole inférieur à <
est utilisé pour rediriger le contenu d’un fichier vers l’entrée standard stdin
d’un processus. Dans ce cas, les données transitent de droite à gauche : le descripteur réaffecté est supposé être 0 à gauche du symbole inférieur à <
et la source de données (un chemin vers un fichier) doit être à droite du symbole inférieur à <
. La commande uniq
, comme la plupart des outils de gestion de texte en ligne de commande, accepte par défaut les données envoyées à l’entrée standard stdin
:
$ uniq -c </tmp/error.txt 2 cat: /proc/cpu_info: No such file or directory
L’option -c
demande à uniq
d’afficher le nombre de fois qu’une ligne répétée apparaît dans le texte. Comme la valeur numérique du descripteur de fichier redirigé a été supprimée, la commande de l’exemple équivaut à uniq -c 0</tmp/error.txt
. Utiliser un descripteur de fichier autre que 0
dans une redirection d’entrée n’a de sens que dans des contextes bien spécifiques, étant donné qu’il est possible pour un programme de demander des données aux descripteurs de fichier 3
, 4
, etc. En effet, les programmes peuvent utiliser n’importe quel nombre entier supérieur à 2 comme nouveau descripteur de fichier pour l’entrée/sortie de données. À titre d’exemple, le code C suivant lit les données depuis le descripteur de fichier 3
et les reproduit simplement vers le descripteur de fichier 4
:
Note
|
Le programme doit gérer correctement ce genre de descripteurs de fichiers, faute de quoi il pourrait tenter une opération de lecture ou d’écriture invalide et entraîner un plantage. |
#include <stdio.h> int main(int argc, char **argv){ FILE *fd_3, *fd_4; // Open file descriptor 3 fd_3 = fdopen(3, "r"); // Open file descriptor 4 fd_4 = fdopen(4, "w"); // Read from file descriptor 3 char buf[32]; while ( fgets(buf, 32, fd_3) != NULL ){ // Write to file descriptor 4 fprintf(fd_4, "%s", buf); } // Close both file descriptors fclose(fd_3); fclose(fd_4); }
Pour tester ce bout de code, enregistrez-le sous le nom de fd.c
et compilez-le avec gcc -o fd fd.c
. Ce programme nécessite que les descripteurs de fichiers 3 et 4 soient disponibles pour qu’il puisse y accéder en lecture et en écriture. Pour donner un exemple, le fichier /tmp/error.txt
créé plus haut pourra être utilisé comme source pour le descripteur de fichier 3
et le descripteur de fichier 4
pourra être redirigé vers la sortie standard stdout
:
$ ./fd 3</tmp/error.txt 4>&1 cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
Du point de vue du développeur, l’utilisation des descripteurs de fichiers évite d’avoir à gérer l’analyse des options et les chemins du système de fichiers. Un seul et même descripteur de fichier peut même être utilisé comme entrée et sortie. Dans ce cas, le descripteur de fichier est défini en ligne de commande avec les symboles inférieur à <
et supérieur à >
, comme dans 3<>/tmp/error.txt
.
Documents en ligne
Une autre manière de rediriger l’entrée fait appel aux méthodes Here document et Here string, également appelées documents en ligne. La redirection Here document permet la saisie d’un texte de plusieurs lignes qui sera utilisé comme contenu redirigé. Un double chevron constitué de deux symboles "inférieur à" <<
indique une redirection Here document :
$ wc -c <<EOF > How many characters > in this Here document? > EOF 43
À droite du double chevron <<
figure le terme de clôture EOF
(End Of File). Le mode d’insertion se termine dès qu’une ligne contenant uniquement ce terme final est saisie. On peut très bien utiliser n’importe quel autre terme pour clôturer, à condition de ne pas insérer d’espace entre le double chevron <<
et le terme final. Dans l’exemple ci-dessus, les deux lignes de texte ont été renvoyées vers l’entrée standard stdin
de la commande wc -c
, qui affiche le nombre de caractères. Tout comme pour la redirection d’entrée pour les fichiers, l’entrée standard stdin
(descripteur de fichier 0
) est supposée si le descripteur de fichier redirigé n’est pas renseigné.
La méthode Here string ressemble beaucoup à la méthode Here document, mais pour une seule ligne :
$ wc -c <<<"How many characters in this Here string?" 41
Dans cet exemple, la chaîne de caractères à droite du triple chevron <<<
est envoyée vers l’entrée standard stdin
de wc -c
, qui compte le nombre de caractères. Les chaînes de caractères contenant des espaces doivent être placées entre guillemets, faute de quoi seul le premier mot sera utilisé comme Here string et les autres seront considérés comme des arguments pour la commande.
Exercices guidés
-
En dehors des fichiers texte, la commande
cat
peut également fonctionner avec des données binaires, pour envoyer le contenu d’un périphérique de type bloc vers un fichier par exemple. En utilisant la redirection, commentcat
peut-il envoyer le contenu du périphérique/dev/sdc
vers le fichiersdc.img
dans le répertoire courant ? -
Quel est le nom du canal standard redirigé par la commande
date 1> now.txt
? -
Après avoir tenté d’écraser un fichier en utilisant la redirection, un utilisateur se retrouve confronté à un message d’erreur indiquant que l’option
noclobber
est activée. Comment peut-il désactiver l’optionnoclobber
pour la session en cours ? -
Quel sera le résultat de la commande
cat <<.>/dev/stdout
?
Exercices d’approfondissement
-
La commande
cat /proc/cpu_info
affiche un message d’erreur parce que/proc/cpu_info
n’existe pas. La commandecat /proc/cpu_info 2>1
redirige le message d’erreur vers où ? -
Est-ce qu’il sera toujours possible de rejeter du contenu renvoyé vers
/dev/null
si l’optionnoclobber
est activée pour la session courante du shell ? -
Sans utiliser
echo
, comment peut-on rediriger le contenu de la variable$USER
vers l’entrée standardstdin
de la commandesha1sum
? -
Le noyau Linux conserve des liens symboliques dans
/proc/PID/fd/
vers chaque fichier ouvert par un processus, où PID est le numéro d’identification du processus correspondant. Comment l’administrateur système pourrait-il utiliser ce répertoire pour vérifier l’emplacement des fichiers logs ouverts parnginx
, en supposant que son PID est1234
? -
Il est possible d’effectuer des calculs arithmétiques en utilisant les seules commandes intégrées à l’interpréteur de commandes, mais les calculs en virgule flottante nécessitent des programmes spécifiques comme
bc
(basic calculator).bc
permet même de spécifier le nombre de décimales, grâce au paramètrescale
. En revanche,bc
n’accepte les opérations que par l’entrée standard, généralement saisies en mode interactif. En utilisant un Here string, comment peut-on envoyer l’opération en virgule flottantescale=6 ; 1/3
vers l’entrée standard debc
?
Résumé
Cette leçon aborde les méthodes qui permettent d’exécuter un programme en redirigeant ses canaux de communication standard. Les processus Linux utilisent ces canaux standard comme descripteurs de fichiers génériques pour lire et écrire des données, ce qui permet de les convertir à volonté en fichiers ou en périphériques. La leçon comporte les étapes suivantes :
-
Que sont les descripteurs de fichiers et quel est leur rôle sous Linux.
-
Les canaux de communication standard de chaque processus : stdin, stdout et stderr.
-
Comment exécuter correctement une commande en utilisant la redirection des données, en entrée comme en sortie.
-
Comment utiliser les documents en ligne dans les redirections d’entrée.
Voici les procédures et les commandes abordées :
-
Opérateurs de redirection :
>
,<
,>>
,<<
,<<<
. -
Commandes
cat
,set
,uniq
etwc
.
Réponses aux exercices guidés
-
En dehors des fichiers texte, la commande
cat
peut également fonctionner avec des données binaires, pour envoyer le contenu d’un périphérique de type bloc vers un fichier par exemple. En utilisant la redirection, commentcat
peut-il envoyer le contenu du périphérique/dev/sdc
vers le fichiersdc.img
dans le répertoire courant ?$ cat /dev/sdc > sdc.img
-
Quel est le nom du canal standard redirigé par la commande
date 1> now.txt
?Sortie standard ou
stdout
-
Après avoir tenté d’écraser un fichier en utilisant la redirection, un utilisateur se retrouve confronté à un message d’erreur indiquant que l’option
noclobber
est activée. Comment peut-il désactiver l’optionnoclobber
pour la session en cours ?set +C
ouset +o noclobber
-
Quel sera le résultat de la commande
cat <<.>/dev/stdout
?Bash entrera en mode de saisie Heredoc, puis en sortira lorsqu’un point apparaîtra tout seul sur une ligne. Le texte saisi sera redirigé vers la sortie standard
stdout
( affiché à l’écran).
Réponses aux exercices d’approfondissement
-
La commande
cat /proc/cpu_info
affiche un message d’erreur parce que/proc/cpu_info
n’existe pas. La commandecat /proc/cpu_info 2>1
redirige le message d’erreur vers où ?Vers un fichier nommé
1
dans le répertoire courant. -
Est-ce qu’il sera toujours possible de rejeter du contenu renvoyé vers
/dev/null
si l’optionnoclobber
est activée pour la session courante du shell ?Oui.
/dev/null
est un fichier spécial non affecté parnoclobber
. -
Sans utiliser
echo
, comment peut-on rediriger le contenu de la variable$USER
vers l’entrée standardstdin
de la commandesha1sum
?$ sha1sum <<<$USER
-
Le noyau Linux conserve des liens symboliques dans
/proc/PID/fd/
vers chaque fichier ouvert par un processus, où PID est le numéro d’identification du processus correspondant. Comment l’administrateur système pourrait-il utiliser ce répertoire pour vérifier l’emplacement des fichiers logs ouverts parnginx
, en supposant que son PID est1234
?En exécutant la commande
ls -l /proc/1234/fd
, qui va afficher les cibles de chaque lien symbolique dans le répertoire. -
Il est possible d’effectuer des calculs arithmétiques en utilisant les seules commandes intégrées à l’interpréteur de commandes, mais les calculs en virgule flottante nécessitent des programmes spécifiques comme
bc
(basic calculator).bc
permet même de spécifier le nombre de décimales, grâce au paramètrescale
. En revanche,bc
n’accepte les opérations que par l’entrée standard, généralement saisies en mode interactif. En utilisant un Here string, comment peut-on envoyer l’opération en virgule flottantescale=6 ; 1/3
vers l’entrée standard debc
?$ bc <<<"scale=6; 1/3"