Les redirections permettent de faire communiquer des applications entre elles.
Vous allez faire différentes manipulation et surtout observer ce qui se passe.
Toute commande exécutée s’affichera dans le terminal courant.
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
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.txtQue constatez-vous ?
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.txtLa commande cat sert à afficher dans la sortie standard
le contenu d’un fichier:
$ cat bonjour.txt
Bonjour le mondeIl 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.
Tapez la commande suivante:
$ rm hello.txt > /dev/null
rm: hello.txt: No such file or directoryCette 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:
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.
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.txtUne erreur est survenue ici: un des fichiers est absent.
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.txtEt maintenant, la commande suivante:
$ ls -l hello.txt bonjour.txt > /dev/null
ls: hello.txt: No such file or directoryCette fois, seule l’erreur est affichée.
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
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
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/nullPour afficher uniquement les messages d’erreur:
grep network /etc/* > /dev/nullNous allons maintenant rediriger vers des fichiers:
$ ls -l hello.txt bonjour.txt > fichier
ls: hello.txt: No such file or directoryPuis taper la commande cat fichier : que constatez-vous
? est-ce normal ?
$ 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 ?
Maintenant, nous allons combiner les deux :
$ ls -l hello.txt bonjour.txt > fichier 2> erreur
Ce qui suit donne des informations sur les commandes précédentes.
Expérience 1 - Créer le fichier
bonjour.txt :
$ touch bonjour.txtExpérience 2 - Supprimer le fichier
hello.txt (qu’il existe ou non):
$ rm hello.txt > /dev/nullExpé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.txtExpé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 directoryExpé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.txtExpérience 6 - Affichage du contenu du fichier
erreur :
$ cat erreur
ls: cannot access 'hello.txt': No such file or directoryExpérience 7 - Affichage du contenu du fichier
erreur :
$ cat sortie
-rw-rw-r-- 1 laurent laurent 8 févr. 27 12:12 bonjour.txtExpérience 8 - Redirection des deux flux de sortie dans des fichiers:
$ ls -l bonjour.txt hello.txt 2> erreur 1> sortieExpé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.txtExpérience 10 - Concaténation des deux flux de sortie dans des fichiers :
$ ls -l bonjour.txt hello.txt >& sortie-et-erreurExé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.mdAfficher le contenu de ce fichier.
Exécuter la commande suivante:
cat README.md bonjour.txtComment faire pour que ce contenu soit directement enregistré dans un
fichier nommé BONJOUR.md ?
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.
|
|& redirige stderr vers
stdout
La commande suivante permet d’afficher les informations réseau:
ip aIl est possible de ne récupérer qu’une partie des lignes avec les commandes suivantes:
ip a | head -1
ip a | tail -1Essayer ces commandes en remplaçant -1 par
-2, -3, etc
La commande grep permet de sélectionner
certaines lignes :
ip a | grep inetLa 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/ -f1Essayer cette commande en remplaçant -f1 par
-f2.
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
unBien noter la différence de comportement par rapport à
awk:
$ echo " un deux trois quatre" | awk '{print $2}'
deuxUtilisation 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
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 -> ancienSi 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
43Puis, à 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 -> ancienLancer 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 -lfEn 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 | lessPour 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 killEvidemment, 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 ?
Lancer la commande suivante:
echo 'Bonjour les gens, comment allez-vous ?' | tr 'a-z' 'A-Z'Que permet de faire la commande tr ?
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}' | revLes file descriptors (ou fd) permettent de définir des emplacement de redirection.
Il y a trois fd par défaut:
On redirige en utilisant les opérateurs de redirection
(> ou 2>) vers un fd.
Un fd est noté: &n où n 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.txtL’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.txtVoici 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 à >&2Exé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 standardlessPour 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 | lessSyntaxe simplifiée:
ls -l bonjour.txt hello.txt |& lessLa 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.txtIl 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/awkFaites en sorte que l’exécution de la commande ls -l
/usr/bin/nmt* :
information.logFaites en sorte que l’exécution de la commande ls -l hello.txt
bonjour.txt :
information.logVous pouvez passer cette partie si vous le souhaitez: dans un premier temps, les informations qui y sont données ne sont pas indispensables.
fd du
shell courantL’astuce consiste à utiliser la variable spéciale $$ qui
contient l’identifiant du processus courant:
ls -l /proc/$$/fdfdOuvrir un fd se fait en utilisant la commande exec
exec 3<> /tmp/testfdIl s’utilise ensuite comme les fd par défaut
echo bonjour >&3
echo je suis ici >&3
echo je suis encore la >&3Il est possible (et recommandé) de le fermer quand il n’est plus utile.
exec 3>&-
Que devrait afficher la commande suivante ?
cat /tmp/testfdQue peut-on en conclure ?
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.txtLe 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
$3>&1 : redirige une nouvelle sortie vers la
sortie 1 (stdout)1>&2 : redirige la sortie standard (1 =
stdout) vers la sortie d’erreur (2 = stderr)2>&3 : redirige la sortie 2 (stderr)
vers la sortie 3 (qui a été redirigée vers stdout en 1)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.shIl 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.shPour 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.
Créer un fichier contenant les réponses à donner au script. Ici, les réponses à donner sont les suivantes:
Juan)Formell)70)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.
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 :
<< ou
<<-)EOF)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.
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"
EOFExécuter ce fichier, constater.
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"
EOFExécuter ce fichier, constater.
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"
EOFOn aurait pu utiliser des double-quotes, avec le même effet:
cat <<-"EOF"
$je_ne_suis_pas_interpretee
EOFExécuter ce fichier, constater.