Les redirections

Sommaire

Index

Introduction

Les redirections permettent de faire communiquer des applications entre elles.

Vous allez faire différentes manipulation et surtout observer ce qui se passe.

Les sorties UNIX

La sortie principale

Toute commande exécutée s’affichera dans le terminal courant.

Sortie standard

Par exemple ici, la commande ls -lA affiche:

total 12
-rw-r--r--. 1 supv supv  18  8 nov.   2019 .bash_logout
-rw-r--r--. 1 supv supv 141  8 nov.   2019 .bash_profile
-rw-r--r--. 1 supv supv 312  8 nov.   2019 .bashrc

Création d’un fichier

La commande touch permet de créer un fichier vide (ou de changer sa date de modification, comme le manuel peut l’expliquer).

Taper les commandes suivantes:

$ touch bonjour.txt
$ cat bonjour.txt

Que constatez-vous ?

Première redirection vers la sortie standard

Nous allons maintenant écrire dans le fichier grâce au caractère >. Ce caractère redirige la sortie de la commande qui le précède vers un fichier.

$ echo Bonjour le monde
Bonjour le monde
$ echo Bonjour le monde > bonjour.txt

La commande cat sert à afficher dans la sortie standard le contenu d’un fichier:

$ cat bonjour.txt
Bonjour le monde

Il est possible de rediriger vers un fichier qui ne stocke aucune information.

C’est le fichier spécial /dev/null: l’équivalent d’un trou noir duquel rien de ce qui entre ne ressort.

$ echo Bonjour le monde > /dev/null
$

Il ne se passe rien et c’est normal.

La sortie d’erreur

Tapez la commande suivante:

$ rm hello.txt > /dev/null
rm: hello.txt: No such file or directory

Cette fois la redirection semble ne pas avoir marché puisque quelque chose s’est affiché.

En fait, la redirection a bien eu lieu. Mais un programme a une deuxième sortie: la sortie d’erreur.

Par défaut, cette sortie est aussi redirigée vers le terminal courant:

Sortie d’erreurs

Elle permet à un processus de communiquer les problèmes qu’il peut rencontrer au cours de son exécution, même si sa sortie standard est redirigée vers un fichier ou un autre programme.

Choisir la bonne sortie

Tout vers une même sortie

Tapez la commande suivante:

$ ls -l hello.txt bonjour.txt
ls: hello.txt: No such file or directory
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt

Une erreur est survenue ici: un des fichiers est absent.

Sortie de la commande

Tapez la commande suivante, qui ne provoque pas d’erreur :

$ ls -l bonjour.txt
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt

Faire disparaître la sortie standard

Et maintenant, la commande suivante:

$ ls -l hello.txt bonjour.txt > /dev/null
ls: hello.txt: No such file or directory

Cette fois, seule l’erreur est affichée.

Sortie de la commande

Faire disparaître la sortie d’erreur

Maintenant, nous allons la faire disparaître en la redirigeant vers /dev/null en utilisant 2> :

$ ls -l hello.txt bonjour.txt 2> /dev/null
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt
Sortie de la commande

Tout faire disparaître

Puis tout faire disparaître en la redirigeant tout vers /dev/null en utilisant 2> et > :

$ ls -l hello.txt bonjour.txt > /dev/null 2> /dev/null
Sortie de la commande

Qu’en pensez-vous ? Faites un schéma qui récapitule ce qui s’est passé pour chaque commande.

Exemple d’utilisation courante de /dev/null

grep network /etc/*

La commande précédente affiche les messages d’erreurs à côté des messages d’information de grep

Pour supprimer les messages d’erreur:

grep network /etc/* 2> /dev/null

Pour afficher uniquement les messages d’erreur:

grep network /etc/* > /dev/null

Rediriger la sortie standard vers un fichier

Nous allons maintenant rediriger vers des fichiers:

$ ls -l hello.txt bonjour.txt > fichier
ls: hello.txt: No such file or directory

Puis taper la commande cat fichier : que constatez-vous ? est-ce normal ?

Sortie de la commande

Rediriger la sortie d’erreur vers un fichier

$ ls -l hello.txt bonjour.txt 2> erreur
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt
$

Que contient le fichier erreur ?

Sortie de la commande

Tout rediriger vers des fichiers

Maintenant, nous allons combiner les deux :

$ ls -l hello.txt bonjour.txt > fichier 2> erreur
Sortie de la commande

Expéricences complémentaires

Ce qui suit donne des informations sur les commandes précédentes.

Expérience 1 - Créer le fichier bonjour.txt :

$ touch bonjour.txt

Expérience 2 - Supprimer le fichier hello.txt (qu’il existe ou non):

$ rm hello.txt > /dev/null

Expérience 3 - Tenter de lister les deux fichiers :

$ ls -l  bonjour.txt hello.txt
ls: cannot access 'hello.txt': No such file or directory
-rw-rw-r-- 1 laurent laurent 8 févr. 27 12:12 bonjour.txt

Expérience 4 - La même commande en redirigeant le flux standard (stdout) vers sortie :

$ ls -l  bonjour.txt hello.txt > sortie
ls: cannot access 'hello.txt': No such file or directory

Expérience 5 - La même commande en redirigeant le flux d’erreur (stderr) vers erreur :

$ ls -l  bonjour.txt hello.txt 2> erreur
-rw-rw-r-- 1 laurent laurent 8 févr. 27 12:12 bonjour.txt

Expérience 6 - Affichage du contenu du fichier erreur :

$ cat erreur
ls: cannot access 'hello.txt': No such file or directory

Expérience 7 - Affichage du contenu du fichier erreur :

$ cat sortie
-rw-rw-r-- 1 laurent laurent 8 févr. 27 12:12 bonjour.txt

Expérience 8 - Redirection des deux flux de sortie dans des fichiers:

$ ls -l bonjour.txt hello.txt 2> erreur 1> sortie

Expérience 9 - Affichage des contenus des deux fichiers:

$ cat erreur
ls: cannot access 'hello.txt': No such file or directory
$ cat sortie
-rw-rw-r-- 1 laurent laurent 8 févr. 27 12:12 bonjour.txt

Expérience 10 - Concaténation des deux flux de sortie dans des fichiers :

$ ls -l bonjour.txt hello.txt >& sortie-et-erreur

Ajouter du contenu dans un fichier

Exécuter les commandes suivantes:

echo '# A propos' > README.md
echo 'Je suis un fichier informatif' >> README.md
echo 'Ma création a été réalisée en plusieurs opérations' >> README.md

Afficher le contenu de ce fichier.

Exécuter la commande suivante:

cat README.md bonjour.txt

Comment faire pour que ce contenu soit directement enregistré dans un fichier nommé BONJOUR.md ?

Redirections entre programmes

Il est possible de donner la sortie d’un programme en entrée d’un autre programme.

C’est une des fonctionnalités majeures d’UNIX/Linux : on peut créer une transformation complexe à partir de transformations simples.

Filtrage des sorties

Utilisation des tuyaux |

Affichage simple

cat README.md

Affichage filtré

grep suis README.md

Affichage redirigé et filtré

cat redirigé vers grep

Intérêt de la sortie d’erreur

Les erreurs ne sont pas filtrées

Filtrer aussi la sortie d’erreur

|& redirige stderr vers stdout

Redirection de stderr et stdout

Récupération d’adresse IP

La commande suivante permet d’afficher les informations réseau:

ip a

Il est possible de ne récupérer qu’une partie des lignes avec les commandes suivantes:

ip a | head -1
ip a | tail -1

Essayer ces commandes en remplaçant -1 par -2, -3, etc

La commande grep permet de sélectionner certaines lignes :

ip a | grep inet

La commande awk permet (entre autre) de sélectionner les champs d’une lignes :

ip a | awk '{print $1}'

Essayer cette commande en remplaçant $1 par $2, etc

On peut donc chaîner ces commandes:

ip a | grep inet | tail -n 1 | awk '{ print $2 }'

Et ajouter autant d’opérations que souhaité:

ip a | grep inet | tail -n 1 | awk '{ print $2 }' | cut -d/ -f1

Essayer cette commande en remplaçant -f1 par -f2.

Exemples supplémentaires avec cut

$ echo "1,2,3,4,5"
1,2,3,4,5
$ echo "1,2,3,4,5" | cut -d, -f2
2
$ echo "un,deux,trois,quatre,cinq" | cut -d, -f2
deux
$ echo "un,deux, trois,quatre ,cinq" | cut -d, -f2
deux
$ echo "un,deux, trois,quatre ,cinq" | cut -d, -f3-
 trois,quatre ,cinq
$ echo "un,deux, trois,quatre ,cinq" | cut -d, -f2-4
deux, trois,quatre
$ echo "un,deux, trois,quatre ,cinq" | cut -d" " -f2
trois,quatre
$ echo " un  deux   trois quatre" | cut -d" " -f2
un

Bien noter la différence de comportement par rapport à awk:

$ echo " un  deux   trois quatre" | awk '{print $2}'
deux

Application : stockage dans une variable

Utilisation de la substitution de commande (command substitution)

Utilisation du backtick ```:

$ adresse_ip=`ip a | grep ens | tail -n 1 | awk '{print $2}' | awk -F/ '{print $1}'`
$ echo $adresse_ip
192.168.21.11

Utilisation de la substitution de commande $(...):

$ adresse_ip=$(ip a | grep ens | tail -n 1 | awk '{print $2}' | awk -F/ '{print $1}')
$ echo $adresse_ip
192.168.21.11

Autre exemple d’utilisation des redirections

La commande suivante affiche de nombreuses informations.

$ ls -l
total 16
-rw-rw-r-- 1 ian ian    0 déc.   7 14:47 adaptable
-rw-rw-r-- 1 ian ian    0 déc.   7 14:48 cap
lrwxrwxrwx 1 ian ian    6 déc.   8 14:17 lien_vers_ancien -> ancien

Si nous souhaitons afficher la dernière partie (la colonne affichant les noms de fichier), on va chercher à supprimer les caractères du début de la ligne.

Pour cela, on va commencer par compter ces caractères (commande wc) :

$ echo "-rw-rw-r-- 1 ian ian    0 déc.   7 14:47 " | wc -c
43

Puis, à l’aide de la commande cut, on peut désormais découper chaque ligne affichée:

$ ls -l | cut -c43-

adaptable
cap
lien_vers_ancien -> ancien

Automatisation de tâches

Lancer les commandes suivantes:

sleep 2001 &
sleep 2002 &

Ouvrir un nouveau terminal (en gardant le précédent ouvert) et une nouvelle session sur votre machine.

Exécuter la commande suivante:

$ ps -lf
F S UID         PID   PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
0 S laurent    1613   1612  0  80   0 -  5240 -      11:15 pts/1    00:00:00 -bash
0 R laurent    1698   1613  0  80   0 -  9577 -      11:33 pts/1    00:00:00 ps -lf

En exécutant la commande ps -elf, la sortie est beaucoup plus verbeuse. Exécuter la commande suivante et trouver la commande sleep 2001 précédemment lancée:

ps -elf | less

Pour que la commande suivante fonctionne correctement, il est nécessaire de relancer les commandes sleep qui auraient été tuées précédemment.

Pour tuer cette commande, on peut lancer la commande kill suivie du numéro de processus (PID). Cependant, on peut automatiser cela ainsi:

ps -elf | grep 'sleep 2001' |grep -v grep | awk '{print $4}' | xargs kill

Evidemment, cette commande est dangereuse: elle permet de tuer tous les processus correspondant au paramètre du premier grep.

Lancer et analyser la commande:

ps -elf | grep 'sleep' |grep -v grep | awk '{print $4}'

Que font chacune des opérations ?

Que se passe-t-il si on ajoute une commande xargs kill à la fin ?

Transformation de contenu

Lancer la commande suivante:

echo 'Bonjour les gens, comment allez-vous ?' | tr 'a-z' 'A-Z'

Que permet de faire la commande tr ?

En inversant l’ordre des caractères

echo 'Bonjour les gens, comment allez-vous ?' | tr 'a-z' 'A-Z'
echo 'Bonjour les gens, comment allez-vous ?' | tr 'a-z' 'A-Z' | rev
echo 'Bonjour les gens, comment allez-vous ?' | tr 'a-z' 'A-Z' | rev | awk '{$1="!!!" ; print}'
echo 'Bonjour les gens, comment allez-vous ?' | tr 'a-z' 'A-Z' | rev | awk '{$1="!!!" ; print}' | rev

Descripteurs de fichiers

Les file descriptors (ou fd) permettent de définir des emplacement de redirection.

Il y a trois fd par défaut:

Utilisation

On redirige en utilisant les opérateurs de redirection (> ou 2>) vers un fd.

Un fd est noté: &nn est le numéro du fd. Par exemple, &1 désigne standard output:

$ ls -l hello.txt bonjour.txt  > sortie.log 2>&1
$ cat sortie.log
ls: hello.txt: No such file or directory
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt

L’ordre a de l’importance:

$ ls -l hello.txt bonjour.txt 2>&1 > sortie.log
ls: hello.txt: No such file or directory
$ cat sortie.log
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt

Démonstration des file descriptor

Voici un code à placer dans un fichier nommé demoredir :

echo "Ci-dessous: la valeur du fichier de sortie stdout:"
readlink $(readlink /dev/stdout)

echo "Ci-dessous: la valeur du fichier de sortie stderr:"
readlink $(readlink /dev/stderr)

echo "Un message standard"
echo "Un message d'erreur" >&2 # &2 = File Descriptor n°2

# 2>&1
# 1>&2 est équivalent à >&2

Exécuter la commande chmod +x demoredir

Observons ce qui se passe à l’exécution:

$ ./demoredir > essairedir 2>&1
$ cat essairedir
Ci-dessous: la valeur du fichier de sortie stdout:
/home/laurent/essairedir
Ci-dessous: la valeur du fichier de sortie stderr:
/home/laurent/essairedir
Un message standard
Un message d'erreur
$ ./demoredir > essairedir
Un message d'erreur
$ cat essairedir
Ci-dessous: la valeur du fichier de sortie stdout:
/home/laurent/essairedir
Ci-dessous: la valeur du fichier de sortie stderr:
/dev/pts/2
Un message standard

Redirection dans less

Pour afficher les messages d’erreur dans less, il faut donc penser à rediriger la sortie d’erreur dans la sortie standard:

$ ls -l hello.txt bonjour.txt 2>&1 | less

Syntaxe simplifiée:

ls -l bonjour.txt hello.txt |& less

Ecrire vers la sortie et vers un fichier en même temps

La commande tee afficher l’entrée standard (standard input) qu’elle reçoit vers la sortie standard et vers le fichier donné en paramètre:

$ ls -l hello.txt bonjour.txt | tee output.log
ls: hello.txt: No such file or directory
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt
$ cat output.log
-rw-r--r--  1 lauhub  staff  17 26 mar 11:02 bonjour.txt

Il est même possible d’ajouter des données avec tee :

$ ls -l /usr/bin/awk | tee -a output.log
lrwxrwxrwx 1 root root 21 Jul  2 13:47 /usr/bin/awk -> /etc/alternatives/awk
$ cat output.log
-rw-r--r-- 1 laurent laurent 8 Jul  3 12:04 bonjour.txt
lrwxrwxrwx 1 root root 21 Jul  2 13:47 /usr/bin/awk -> /etc/alternatives/awk

Faites en sorte que l’exécution de la commande ls -l /usr/bin/nmt* :

Faites en sorte que l’exécution de la commande ls -l hello.txt bonjour.txt :

Créer ses propres file descriptors

Information sur cette partie

Vous pouvez passer cette partie si vous le souhaitez: dans un premier temps, les informations qui y sont données ne sont pas indispensables.

Lister les fd du shell courant

L’astuce consiste à utiliser la variable spéciale $$ qui contient l’identifiant du processus courant:

ls -l /proc/$$/fd

Création de fd

Ouvrir un fd se fait en utilisant la commande exec

exec 3<> /tmp/testfd

Il s’utilise ensuite comme les fd par défaut

echo bonjour >&3
echo je suis ici >&3
echo je suis encore la >&3

Il est possible (et recommandé) de le fermer quand il n’est plus utile.

exec 3>&-

Que devrait afficher la commande suivante ?

cat /tmp/testfd

Que peut-on en conclure ?

Exemple : inversion des sorties

Si on souhaite filtrer la sortie d’erreur pour en récupérer une partie :

$ ls hello.txt bonjour.txt
ls: cannot access 'hello.txt': No such file or directory
bonjour.txt

Le filtre est opéré par défaut sur la sortie standard (n°1):

$ ls hello.txt bonjour.txt | awk -F: '{print $3}'
ls: cannot access 'hello.txt': No such file or directory

$

Pour inverser la sortie on va utiliser un fd intermédiaire:

$ ls hello.txt bonjour.txt 3>&1 1>&2 2>&3 |  awk -F: '{print $3}'
bonjour.txt
 No such file or directory
$

Explications

  1. 3>&1 : redirige une nouvelle sortie vers la sortie 1 (stdout)
  2. 1>&2 : redirige la sortie standard (1 = stdout) vers la sortie d’erreur (2 = stderr)
  3. 2>&3 : redirige la sortie 2 (stderr) vers la sortie 3 (qui a été redirigée vers stdout en 1)

Redirection entrante (input redirection)

Exécution d’un script

Par exemple, créer le fichier texte script.sh avec le contenu suivant:

echo "Quel est ton prénom ? "
read
prenom=$REPLY

echo "Quel est ton nom ? "
read
nom=$REPLY

echo "Donne-moi ton âge: "
read age

echo "Salut $prenom $nom, tu as $age ans."

Pour exécuter ce script, au moins deux possibilités.

La première en appelant la commande bash suivie du nom du script :

bash script.sh

Il est possible de créer un fichier permettant d’automatiser les entrées au clavier pour un programme.

Nous allons maintenant rendre le fichier script.sh exécutable (nous verrons plus en détail les droits et permissions dans un autre chapitre):

chmod +x script.sh

Pour exécuter le script, il suffit maintenant d’appeler la commande suivante:

./script.sh

./ permet de dire que le script se trouve explicitement dans le dossier courant. Ceci est nécessaire car il n’est pas dans un chemin pris en charge par la variable PATH.

Voici un exemple d’exécution du script:

$ bash script.sh
Quel est ton prénom ?
Juan
Quel est ton nom ?
Formell
Donne-moi ton âge:
70
Salut Juan Formell, tu as 70 ans.

Redirection entrante pour réponse automatisée

Créer un fichier contenant les réponses à donner au script. Ici, les réponses à donner sont les suivantes:

Voici le contenu du fichier correspondant (reponses.txt):

Juan
Formell
70

Il est possible de donner les réponses au script directement par une redirection entrante:

$ ./script.sh < reponses.txt
Quel est ton prénom ?
Quel est ton nom ?
Donne-moi ton âge:
Salut Juan Formell, tu as 70 ans.

Ici, c’est le fichier reponses.txt qui a remplacé les entrées faites au clavier par l’utilisateur.

Here Document

Un Here Document (ou heredoc) est un fichier créé à la volée et qui permet de fournir les entrées à un programme de manière automatisée.

Il commence en général par :

Il se termine par le délimiteur choisi.

Exemple:

$ ./script.sh <<EOF
Laurent
HUBERT
17
EOF

Ce qui donne à l’exécution:

$ ./script.sh <<EOF
> Laurent
> HUBERT
> 17
> EOF
Quel est ton prénom ?
Quel est ton nom ?
Donne-moi ton âge:
Salut Laurent HUBERT, tu as 17 ans.

Il est possible également d’indenter le texte. C’est le rôle du marqueur <<- (deux chevrons suivis d’un tiret).

Ceci est utile dans un script. Par exemple, ici le contenu du fichier auto.sh (on utilise des tabulations au début des trois lignes données en réponse):

./script.sh <<-FINDEFLUX
  Laurent
  HUBERT
  17
FINDEFLUX

L’exécution de ce script donnera:

$ bash auto.sh
Quel est ton prénom ?
Quel est ton nom ?
Donne-moi ton âge:
Salut Laurent HUBERT, tu as 17 ans.

Exemple d’affichage multi-lignes

Here-document avec interprétation des variables

Créer un fichier et le rendre exécutable après y avoir placé le contenu suivant:

nom_du_programme=$0


cat <<EOF
Bonjour $USER,

Je suis content de t'accueillir sur ce merveilleux système nommé GNU/Linux.

C'est un héritier glorieux de UNIX

Tu viens d'exécuter un script nommé "$nom_du_programme"

EOF

Exécuter ce fichier, constater.

Here-document avec indentation

Créer un fichier et le rendre exécutable après y avoir placé le contenu suivant:

nom_du_programme=$0


cat <<-EOF
Bonjour $USER,

  Je suis content de t'accueillir sur ce merveilleux système nommé GNU/Linux.

  C'est un héritier glorieux de UNIX. Il permet de bien gérer le décalage des marges (indentation).

  Tu viens d'exécuter un script nommé "$nom_du_programme"

EOF

Exécuter ce fichier, constater.

Here-document sans interprétation des variables

Créer un fichier et le rendre exécutable après y avoir placé le contenu suivant:

nom_du_programme=$0

cat <<-'EOF'
Bonjour $USER,

Je suis content de t'accueillir sur ce merveilleux système nommé GNU/Linux.

C'est un héritier glorieux de UNIX. Ici les variables ne sont pas interprétées...

Tu viens d'exécuter un script nommé "$nom_du_programme"

EOF

On aurait pu utiliser des double-quotes, avec le même effet:

cat <<-"EOF"
$je_ne_suis_pas_interpretee
EOF

Exécuter ce fichier, constater.