Chapitre 05
Redirections et tuyaux
Objectifs
À la fin de ce chapitre, tu sauras :
- comprendre les trois flux d'une commande :
stdin,stdout,stderr; - rediriger la sortie d'une commande vers un fichier avec
>et>>; - capter ou ignorer les erreurs séparément du résultat ;
- enchaîner des commandes avec le tuyau
|pour composer des traitements puissants.
Ce chapitre contient l'idée la plus importante de toute la formation. Comprends bien les tuyaux, et le terminal change de dimension.
Trois flux par commande
Chaque commande Unix dispose de trois canaux de communication, qu'on appelle des flux (streams) :
- l'entrée standard, ou
stdin: par où la commande reçoit des données (par défaut, ton clavier) ; - la sortie standard, ou
stdout: par où elle envoie son résultat normal (par défaut, l'écran) ; - la sortie d'erreur, ou
stderr: par où elle envoie ses messages d'erreur (aussi l'écran par défaut).
┌─────────────┐
stdin ─────► │ commande │ ─────► stdout (le résultat)
(clavier) └─────────────┘ ─────► stderr (les erreurs)
À l'écran, stdout et stderr se mélangent et tu ne les distingues pas. Mais ils sont séparés, et
c'est ce qui permet de rediriger le résultat sans emporter les erreurs, ou l'inverse. Tout le
chapitre consiste à détourner ces flux ailleurs que vers l'écran et le clavier.
Rediriger la sortie vers un fichier : `>` et `>>`
Le symbole > envoie stdout dans un fichier au lieu de l'écran :
$ echo "premiere ligne" > notes.txt
$ cat notes.txt
premiere ligne
Rien ne s'est affiché après le echo : le texte est parti dans notes.txt. C'est ainsi qu'on
fabriquait le fichier journal.log au chapitre précédent.
Attention —
>écrase le fichier : son contenu précédent est perdu sans avertissement. Pour ajouter à la fin sans effacer, utilise>>(deux chevrons) :
$ echo "deuxieme ligne" >> notes.txt
$ cat notes.txt
premiere ligne
deuxieme ligne
Retiens la distinction, elle est cruciale :
| Opérateur | Effet | Mnémo |
|---|---|---|
> |
écrit dans le fichier en écrasant | un seul chevron, on remplace |
>> |
ajoute à la fin du fichier | deux chevrons, on empile |
C'est >> qu'on emploiera pour qu'un script écrive son journal sans effacer l'historique à chaque
exécution.
Rediriger l'entrée : `<`
Symétriquement, < fait lire à une commande un fichier au lieu du clavier :
$ wc -l < journal.log
6
Ici wc lit son stdin depuis le fichier. En pratique on écrit plus souvent wc -l journal.log,
mais comprendre < éclaire la logique des flux : une commande ne sait pas d'où viennent ses données,
elle se contente de lire son entrée.
Séparer le résultat des erreurs
Les flux stdout et stderr portent des numéros : 1 pour stdout, 2 pour stderr. On s'en sert
pour les rediriger séparément.
$ ls donnees dossier-inexistant
Cette commande produit à la fois un résultat (le contenu de donnees, sur stdout) et une erreur
(dossier-inexistant n'existe pas, sur stderr). On peut les séparer :
$ ls donnees dossier-inexistant > resultat.txt 2> erreurs.txt
Le résultat normal va dans resultat.txt (> vise stdout, le flux 1), et les erreurs dans
erreurs.txt (2> vise stderr, le flux 2). Deux variantes très courantes :
$ commande 2>/dev/null # jette les erreurs (les rend invisibles)
$ commande > tout.txt 2>&1 # envoie résultat ET erreurs dans le même fichier
/dev/null est un « trou noir » du système : tout ce qu'on y envoie disparaît. 2>&1 se lit
« envoie le flux 2 là où va déjà le flux 1 ».
Astuce —
2>/dev/nullest précieux quand une commande affiche des erreurs sans gravité (par exemple des « permission refusée » lors d'une recherche) qui noient le vrai résultat.
Le tuyau : `|`
Voici l'idée maîtresse. Le tuyau (pipe), noté |, branche le stdout d'une commande
directement sur le stdin de la suivante. Au lieu de passer par un fichier intermédiaire, le résultat
de la première commande devient l'entrée de la seconde :
commande1 │ commande2 │ commande3
stdout ─┘ stdout ─┘
devient devient
stdin de stdin de
commande2 commande3
Un exemple : combien de fichiers .txt dans le dossier courant ?
$ ls *.txt | wc -l
3
ls *.txt produit la liste, le | l'envoie à wc -l qui la compte. Aucune des deux commandes n'a
été conçue pour l'autre : c'est toute la beauté de la philosophie Unix, où chaque outil fait une
chose et se combine avec les autres.
Composer des traitements
La force des tuyaux apparaît quand on en enchaîne plusieurs. Reprenons journal.log :
# Combien de lignes ERROR dans le journal ?
$ grep ERROR journal.log | wc -l
2
# Les 3 dernières lignes contenant "connexion"
$ grep connexion journal.log | tail -n 3
# Les niveaux de log présents, triés et dédoublonnés
$ grep -oE 'INFO|ERROR|WARNING' journal.log | sort | uniq -c
1 WARNING
2 ERROR
3 INFO
Ce dernier exemple introduit trois compagnons des tuyaux, qu'on approfondira au chapitre 7 :
sorttrie les lignes ;uniqregroupe les lignes identiques consécutives (d'où lesortavant) ;-cles compte ;- la combinaison
sort | uniq -cest l'idiome classique pour « compter les occurrences ».
À retenir — Un tuyau
|connecte des commandes en chaîne : chaque maillon transforme le flux et le passe au suivant. C'est en composant de petites commandes qu'on résout de gros problèmes.
Attention — Ne confonds pas
|(tuyau, entre deux commandes) et>(redirection, vers un fichier).commande > fichierécrit dans un fichier ;commande1 | commande2envoie vers une autre commande. On termine souvent une chaîne de tuyaux par une redirection :grep ERROR journal.log | sort > erreurs-triees.txt.
Résumé
- Toute commande a trois flux :
stdin(entrée),stdout(résultat),stderr(erreurs). >redirigestdoutvers un fichier en l'écrasant ;>>ajoute à la fin ;<lit l'entrée depuis un fichier.2>redirige les erreurs ;2>/dev/nullles jette ;> f 2>&1met résultat et erreurs dans le même fichier.- Le tuyau
|branche la sortie d'une commande sur l'entrée de la suivante ; on enchaîne les maillons pour composer des traitements. sort | uniq -ccompte les occurrences (à retenir).
Exercices
Exercice 1 — Construire et nourrir un fichier
- Crée un fichier
fruits.txtcontenantpommesur la première ligne, en écrasant tout contenu précédent. - Ajoute
bananepuispommeà la suite, sans effacer. - Affiche le fichier pour vérifier.
Voir le corrigé
La démarche : > pour la première écriture (écrase), >> pour les ajouts.
$ echo pomme > fruits.txt
$ echo banane >> fruits.txt
$ echo pomme >> fruits.txt
$ cat fruits.txt
pomme
banane
pomme
Si tu avais utilisé > partout, seul le dernier pomme resterait : chaque > écrase le précédent.
Exercice 2 — Compter avec un tuyau
En repartant du fruits.txt de l'exercice 1 :
- Compte le nombre total de lignes avec un tuyau (sans donner le fichier en argument à
wc). - Affiche chaque fruit avec son nombre d'occurrences.
Voir le corrigé
La démarche : cat envoie le contenu dans le tuyau ; wc -l compte ; sort | uniq -c regroupe et
compte les doublons.
$ cat fruits.txt | wc -l
3
$ cat fruits.txt | sort | uniq -c
1 banane
2 pomme
Le sort est indispensable avant uniq, qui ne regroupe que les lignes identiques consécutives.
Sans tri, les deux pomme séparés par banane ne seraient pas regroupés.
Quiz
1. Quelle est la différence entre > et >> ?
- A. Aucune, ce sont des synonymes
- B.
>écrase le fichier,>>ajoute à la fin - C.
>ajoute à la fin,>>écrase le fichier
2. Que fait ls | wc -l ?
- A. Liste les fichiers puis les supprime
- B. Compte le nombre d'éléments listés par
ls - C. Écrit la liste des fichiers dans un fichier nommé
wc
3. À quoi sert 2>/dev/null ?
- A. À envoyer le résultat normal dans un fichier
- B. À faire disparaître les messages d'erreur
- C. À compter les erreurs
4. Dans une chaîne a | b, que reçoit la commande b ?
- A. Le code source de
a - B. La sortie standard (
stdout) dea, sur son entrée standard - C. Rien, le tuyau ne transmet pas de données
Voir les réponses
- B —
>remplace tout le contenu,>>empile à la fin. - B —
lsproduit la liste, le tuyau l'envoie àwc -lqui compte les lignes. - B —
2>vise le flux d'erreur,/dev/nulll'absorbe : les erreurs deviennent invisibles. - B — Le tuyau connecte le
stdoutde la gauche austdinde la droite.
Projet fil rouge
Ton script devra garder une trace de ses actions. Les redirections sont exactement l'outil pour ça : tu vas créer, à la main, le journal des sauvegardes.
-
Écris une première entrée dans un fichier de log dédié, puis vérifie :
$ echo "$(date) - sauvegarde lancee" >> sauvegardes/historique.log $ cat sauvegardes/historique.logLe
$(date)insère la date du moment ; c'est une substitution de commande qu'on détaillera au chapitre 8. Retiens pour l'instant qu'on horodate chaque ligne. -
Refais une copie de
donneeset enregistre le résultat de l'opération dans le même journal, en séparant un éventuel message d'erreur :$ cp -r donnees sauvegardes/donnees-copie2 2>> sauvegardes/historique.log \ && echo "$(date) - copie OK" >> sauvegardes/historique.log
Tu utilises déjà >> pour ne jamais perdre l'historique et 2>> pour y consigner les erreurs : ce
sera le squelette du journal de sauvegarde.sh. Au prochain chapitre, on s'intéresse aux
permissions — qui a le droit de lire, modifier ou exécuter un fichier — une notion indispensable
avant de rendre un script exécutable.