Les redirections

TerminalVoici le septième volet de mon cours d’introduction au shell Bash. La dernière fois, nous avons vu les expressions complexes. Aujourd’hui, nous abordons les redirections, qui sont couramment utilisées dans les commandes Unix.

Les redirections permettent…

  • de récupérer le résultat d’une ou plusieurs commandes dans un fichier ;
  • de faire lire un fichier à une commande.

Entrée et sorties standard des processus

Les processus Unix ont, par défaut, leur fichier terminal ouvert trois fois, sous trois descripteurs de fichiers différents : 0, 1 et 2.

Entrée standard

Le descripteur de fichier 0 est également nommé “entrée standard du processus”. Les processus qui attendent des informations de la part de l’utilisateur déclenchent une requête de lecture sur le descripteur 0. Si ce dernier est associé au terminal, cela se matérialise pour l’utilisateur par une demande de saisie au clavier.

Sortie standard

Le descripteur de fichier 1 est également nommé “sortie standard du processus”. Par convention, un processus qui souhaite envoyer un message résultat à l’utilisateur doit le faire transiter via le descripteur 1. Si ce dernier est associé au terminal, ce qui est le cas par défaut, cela se matérialise pour l’utilisateur par un affichage à l’écran.

Sortie d’erreur standard

Le descripteur de fichier 2 est également nommé “sortie d’erreur standard du processus”. Par convention, un processus qui souhaite envoyer un message d’erreur à l’utilisateur doit le faire transiter via le descripteur 2. Si ce dernier est associé au terminal, ce qui est le cas par défaut, cela se matérialise pour l’utilisateur par un affichage à l’écran.

Redirection des sorties en écriture

La redirection des sorties en écriture permet d’envoyer les affichages liés à un descripteur particulier non plus sur le terminal, mais dans un fichier.

$ commande 1> fichier

Cette commande peut s’écrire plus simplement.

$ commande > fichier

Voici un exemple.

$ touch fichier{1,2,3}
$ ls fichier?
fichier1 fichier2 fichier3
$ ls fichier? > liste
$ cat liste
fichier1
fichier2
fichier3

Si le fichier n’existe pas, il est créé. S’il existe déjà, il est écrasé.

La double redirection permet de concaténer les messages résultant d’une commande au contenu d’un fichier déjà existant.

$ commande 1>> fichier

Là encore, la commande peut s’écrire plus simplement.

$ commande >> fichier

Si le fichier n’existe pas, il est créé. S’il existe déjà, il est ouvert en mode ajout.

Dans l’exemple suivant, on va ajouter la date à la fin du fichier liste créé précédemment.

$ date
ven. janv. 12 15:47:59 CET 2018
$ date >> liste
$ cat liste
fichier1
fichier2
fichier3
ven. janv. 12 15:48:22 CET 2018

La redirection de la sortie d’erreur standard permet de récupérer les messages d’erreur dans un fichier. Les résultats restent à l’écran.

$ commande 2> fichier

Voici un exemple.

$ find / -name passwd 2> erreur
/usr/share/bash-completion/completions/passwd
/usr/bin/passwd
/etc/passwd
/etc/pam.d/passwd
/sys/fs/selinux/class/passwd
/sys/fs/selinux/class/passwd/perms/passwd
$ cat erreur
find: ‘/var/cache/httpd’: Permission non accordée
find: ‘/var/cache/ldconfig’: Permission non accordée
find: ‘/var/cache/cups’: Permission non accordée
...

Là encore, la double redirection de la sortie d’erreur standard permet de concaténer les messages d’erreur d’une commande au contenu d’un fichier existant.

$ commande 2>> fichier

Dans l’exemple suivant, on va concaténer les messages d’erreur de la commande invalide ls -z à la fin du fichier erreur.

$ ls -z
ls : option invalide -- 'z'
Saisissez « ls --help » pour plus d'informations.
$ ls -z 2>> erreur
$ cat erreur
find: ‘/var/cache/httpd’: Permission non accordée
find: ‘/var/cache/ldconfig’: Permission non accordée
find: ‘/var/cache/cups’: Permission non accordée
...
find: ‘/proc/27895/map_files’: Permission non accordée
find: ‘/proc/27895/fdinfo’: Permission non accordée
find: ‘/proc/27895/ns’: Permission non accordée
ls : option invalide -- 'z'
Saisissez « ls --help » pour plus d'informations.

Il est possible de rediriger plusieurs descripteurs sur une même ligne de commande.

$ commande 1> fichier_a 2> fichier_b

Ou encore.

$ commande 2> fichier_b 1> fichier_a

Reprenons l’exemple de tout à l’heure.

$ find / -name passwd 1> resultat 2> erreur
$ cat resultat
/usr/share/bash-completion/completions/passwd
/usr/bin/passwd
/etc/passwd
/etc/pam.d/passwd
/sys/fs/selinux/class/passwd
/sys/fs/selinux/class/passwd/perms/passwd
$ head -n 3 erreur
find: ‘/var/cache/httpd’: Permission non accordée
find: ‘/var/cache/ldconfig’: Permission non accordée
find: ‘/var/cache/cups’: Permission non accordée

L’option noclobber du shell permet de se protéger d’un écrasement involontaire de fichier. Elle est désactivée par défaut.

$ set -o noclobber
$ date > resultat
bash: resultat : impossible d'écraser le fichier existant

Pour forcer l’écrasement il faudra utiliser le symbole de redirection >|.

$ date >| resultat
$ cat resultat
ven. janv. 12 16:02:42 CET 2018

Et voici comment on réactive l’écrasement des fichiers.

$ set +o noclobber

Toutes les plates-formes Unix possèdent un fichier spécial nommé /dev/null qui permet de faire disparaître les affichages. Ce fichier est géré comme un périphérique et n’a pas de notion de contenu. On peut donc considérer qu’il est toujours vide.

$ find / -name passwd 1> resultat 2> /dev/null

Redirection de l’entrée standard

La redirection de l’entrée standard concerne les commandes qui utilisent le descripteur 0, autrement dit celles qui déclenchent une saisie au clavier.

$ commande 0< fichier_message

Cette commande peut s’écrire plus simplement.

$ commande < fichier_message

Dans l’exemple qui suit, on va envoyer un mail à l’utilisateur glagaffe.

$ mail glagaffe
Subject: RDV
Rendez-vous au resto à 13h.
Nico
.
EOT

Pour mettre l’exemple ci-dessus en pratique, il faut que l’utilisateur glagaffe existe et que le serveur mail soit configuré pour la machine locale. Sur un système CentOS, on pourra faire ceci.

# useradd -c "Gaston Lagaffe" glagaffe
# passwd lagaffe
# yum install postfix mailx mutt
# systemctl start postfix

Et pour lire le mail, on pourra s’y prendre comme ceci.

$ su - glagaffe
$ mutt

La commande mail lit l’entrée standard jusqu’à la saisie d’un point . sur une ligne. Les données saisies seront envoyées dans la boîte aux lettres de l’utilisateur glagaffe.

Si l’on souhaite faire lire à la commande mail non plus le clavier mais le contenu d’un fichier, il suffit de connecter le descripteur 0 sur le fichier désiré.

$ cat message
RDV au resto à 13h.
Nico
$ mail -s "RDV" glagaffe < message

Redirections avancées

Pour envoyer la sortie standard et la sortie d’erreur standard dans le même fichier, il faut employer une syntaxe particulière.

$ commande 1> fichier 2>&1

Ou encore…

$ commande 2> fichier 1>&2

Au quotidien, on utilisera plutôt la syntaxe suivante.

$ commande > fichier 2>&1

Reprenons l’exemple de tout à l’heure.

$ find / -name passwd > resultat 2>&1
$ cat resultat
...
/usr/bin/passwd
find: ‘/boot/lost+found’: Permission non accordée
find: ‘/boot/grub2’: Permission non accordée
find: ‘/root’: Permission non accordée

La double redirection en lecture est principalement utilisée dans les scripts shell. Elle permet de connecter l’entrée standard d’une commande sur une portion du script.

$ commande <<ETIQUETTE
données
données
données
ETIQUETTE

Le symbole placé à la suite des caractères << est une déclaration d’étiquette. Elle sera utilisée pour marquer la fin des données à lire. Les lignes insérées entre les deux mots ETIQUETTE seront envoyées sur l’entrée standard de la commande.

Voici un exemple.

$ mail -s "RDV" glagaffe <<FIN
> Rendez-vous au resto à 13h.
> Nico
> FIN

Notez que les étiquettes doivent être immédiatement suivies d’un retour à la ligne.

Rediriger la sortie de la commande ls

Vous avez peut-être essayé de rediriger le résultat de la commande ls comme ceci.

$ ls /etc > config.txt

Le résultat de l’opération est quelque peu inattendu.

$ cat config.txt
adjtime
aliases
aliases.db
alternatives
anacrontab
asound.conf
...

La différence entre les affichages respectifs tient au fait que les développeurs de l’outil ls se sont dit qu’avec un affichage à l’écran, vous préfériez probablement une vue en colonnes, alors que pour une redirection, un affichage avec un élément par ligne serait préférable.

Si l’on souhaite préserver les colonnes dans la redirection, il faut donc l’expliciter à l’aide de l’option -C.

$ ls -C /etc > config.txt
$ cat config.txt
adjtime                  init.d                    qemu-ga
aliases                  inittab                   rc0.d
aliases.db               inputrc                   rc1.d
alternatives             iproute2                  rc2.d
...

En contrepartie, pour être sûr d’obtenir un affichage avec un élément par ligne, on pourra utiliser l’option -1.

$ ls -1 /etc > config.txt

Connecter deux programmes

Dans l’exemple suivant, on prend le résultat d’une commande pour le fournir à une autre commande. Dans un premier temps, on écrit la liste en vrac de tous les paquets du système dans un fichier.

$ rpm -qa > rpms_vrac.txt

Cette liste peut être classée par ordre alphabétique grâce à la commande sort.

$ sort < rpms_vrac.txt

Enfin, le résultat de cette dernière commande peut à son tour être écrit dans un fichier.

$ sort < rpms_vrac.txt > rpms.txt

Voilà ce que ça donne.

$ head rpms.txt
acl-2.2.51-12.el7.x86_64
aic94xx-firmware-30-6.el7.noarch
alsa-firmware-1.0.28-2.el7.noarch
alsa-lib-1.1.3-3.el7.x86_64
alsa-tools-firmware-1.1.0-1.el7.x86_64
audit-2.7.6-3.el7.x86_64
audit-libs-2.7.6-3.el7.x86_64
authconfig-6.2.8-30.el7.x86_64
basesystem-10.0-7.el7.centos.noarch
bash-4.2.46-28.el7.x86_64

Notons que ce genre d’opération s’effectuera plutôt avec des tubes, que nous aborderons dans la prochaine leçon.

Enregistrer une séquence de commandes

Le caractère spécial ; du shell permet d’écrire plusieurs commandes sur une même ligne. Les commandes sont exécutées séquentiellement.

$ date ; pwd ; ls
sam. janv. 13 08:23:43 CET 2018
/home/kikinovak
config.txt message resultat rpms.txt rpms_vrac.txt

Si l’on cherche à enregistrer le résultat de cette séquence, on n’obtient pas le résultat escompté.

$ date ; pwd ; ls > sequence.txt
sam. janv. 13 08:24:50 CET 2018
/home/kikinovak

Les deux premières commandes affichent leur résultat à l’écran, et seule la dernière est redirigée.

La solution consiste ici à utiliser une paire d’accolades {...} pour regrouper les commandes.

$ { date ; pwd ; ls ; } > sequence.txt

Notez bien le caractère ; après la dernière commande.

Documentation

  • Christine Deffaix-Rémy – Programmation shell sous Unix/Linux, pp. 38 – 55
  • Cameron Newham – Learning the Bash shell, pp. 14 – 16
  • Carl Albing – Bash Cookbook – pp. 33 – 44

La suite au prochain numéro.

Ce contenu a été publié dans Bash, Documentation Microlinux, avec comme mot(s)-clé(s) , , . Vous pouvez le mettre en favoris avec ce permalien.

Une réponse à Les redirections

  1. Ping : Les redirections (formation Bash leçon n° 7) - My Tiny Tools

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.