Voici 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.
- Entrée et sorties standard des processus
- Redirection des sorties en écriture
- Redirection de l’entrée standard
- Redirections avancées
- Rediriger la sortie de la commande ls
- Connecter deux programmes
- Enregistrer une séquence de commandes
- Documentation
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.
Ping : Les redirections (formation Bash leçon n° 7) - My Tiny Tools