Comment connecter les commandes entre elles et rediriger leurs flux d'entrée/sortie. Le cœur de la philosophie Unix : chaque programme fait une chose simple, on les compose en pipelines.
Redirections
Tout processus naît avec trois descripteurs ouverts par défaut : 0 (stdin, l'entrée), 1 (stdout, la sortie standard) et 2 (stderr, le canal d'erreur). Les opérateurs ci-dessous redirigent ces descripteurs vers ou depuis des fichiers.
>
Rediriger la sortie standard vers un fichier (en écrasant)
Envoie tout ce que la commande écrit sur stdout (descripteur 1) dans un fichier. Si le fichier existe déjà, il est écrasé sans avertissement ; sinon il est créé.
Capture la liste détaillée dans liste.txt. Le contenu précédent du fichier est perdu.
$ echo "version $(uname -r)" > info.txt
Écrit une seule ligne dans le fichier, en remplaçant son contenu.
Piège classique :
le shell ouvre et tronque le fichier avant de lancer la commande. sort fichier > fichier détruit donc l'entrée avant qu'elle ne soit lue. Passer par un temporaire, ou utiliser sort fichier -o fichier.
Variante non destructive de > : la sortie est ajoutée à la fin du fichier. S'il n'existe pas, il est créé. C'est l'opérateur naturel pour les journaux et les fichiers cumulatifs.
Syntaxe
commande >> fichier
commande 2>> erreurs.log # idem pour stderr
$ date >> activite.log
Ajoute la date courante en fin de activite.log, ligne après ligne.
Branche le descripteur 0 (stdin) sur un fichier. La commande lit comme si elle recevait une saisie clavier, sauf que la source est le fichier. Beaucoup de commandes acceptent aussi un nom de fichier en argument : la différence pratique est que certaines (comme wc) n'affichent pas le nom de fichier en sortie quand on passe par <.
Syntaxe
commande < fichier
$ wc -l < access.log
12483
Compte les lignes sans afficher le nom du fichier (contrairement à wc -l access.log).
$ mysql -u admin maBase < dump.sql
Rejoue un export SQL en injectant le fichier sur stdin de mysql.
Raccourci Bash pour > fichier 2>&1. Tout ce que produit la commande, qu'il s'agisse de sortie normale ou d'erreurs, atterrit dans le même fichier. Variante &>> pour ajouter.
Syntaxe
commande &> fichier
commande &>> fichier # ajout
$ make &> build.log
Tout l'output de la compilation est consigné dans build.log, succès ou échec.
Portabilité :&> est une extension Bash (et Zsh). Dans un script destiné au pur sh ou à dash, préférer la forme portable > fichier 2>&1.
Duplique le descripteur 1 (stdout) sur le descripteur 2 (stderr) : tout ce qui partait sur stderr suivra désormais le même chemin que stdout. C'est la forme portable pour mélanger les deux flux.
Syntaxe
commande > fichier 2>&1 # ordre important : redirection puis dup
$ ./run-tests.sh > tests.log 2>&1
Capture stdout et stderr dans tests.log, version POSIX-compatible.
$ (cmd1; cmd2) 2>&1 | tee both.log
Dans un pipe, on doit fusionner stderr dans stdout pour que tee voie aussi les erreurs.
L'ordre compte.cmd > fichier 2>&1 redirige stdout vers le fichier, puis fait pointer stderr là où stdout pointe — donc le fichier. C'est le bon ordre. cmd 2>&1 > fichier fait l'inverse : il duplique stderr sur le terminal (où stdout pointait encore), puis seulement après redirige stdout. Stderr finit alors sur le terminal, pas dans le fichier.
Le « trou noir » : un fichier qui jette tout ce qu'on y écrit
Pseudo-fichier spécial fourni par le noyau. Toute écriture y disparaît silencieusement, et toute lecture renvoie EOF (fin de fichier) immédiatement. Indispensable pour faire taire des sorties qu'on ne veut pas voir.
$ long-script.sh > /dev/null 2>&1
Lance le script en silence total, ni sortie normale ni erreurs ne s'affichent.
$ if grep -q "ERROR" log 2> /dev/null; then echo "Erreurs trouvées"; fi
grep -q ne produit aucune sortie de correspondance ; le test utilise son statut. La redirection 2>/dev/null masque ses diagnostics, y compris les erreurs de lecture, qui sont alors également traitées comme un résultat non trouvé par ce if.
$ < /dev/null cmd
Lance cmd avec une entrée vide, utile pour les scripts qui ne doivent pas attendre le clavier.
Le pipe est l'outil emblématique d'Unix : il branche la sortie d'un processus directement sur l'entrée d'un autre, sans passer par un fichier intermédiaire. Tous les processus du pipeline tournent en parallèle.
|
Connecter stdout d'une commande à stdin de la suivante
Crée un tampon mémoire entre deux processus. cmd1 | cmd2 lance les deux en parallèle : ce que cmd1 écrit sur stdout est lu par cmd2 sur son stdin. Les pipes se chaînent à volonté.
Syntaxe
cmd1 | cmd2 | cmd3 | ...
$ ps aux | grep nginx | grep -v grep
Filtre les processus contenant « nginx », sans inclure la ligne grep elle-même.
$ sort access.log | uniq -c | sort -rn | head
Pipeline classique d'analyse de logs : trie, compte les doublons, retrie par fréquence, garde le top 10.
$ du -sh */ | sort -h | tail -5
Repère les 5 plus gros sous-dossiers du répertoire courant.
Bufferisation :
Beaucoup de programmes utilisant stdio changent leur buffering selon la destination de stdout : par ligne vers un terminal et par blocs vers un fichier ou un pipe. Ce n’est pas une propriété universelle du descripteur. Un grep placé avant un autre pipe peut retarder l’affichage ; utiliser alors grep --line-buffered, sed -u ou, si compatible, stdbuf -oL.
Raccourci Bash 4+ pour 2>&1 | : envoie à la fois stdout et stderr de la commande de gauche dans la commande de droite. Pratique pour passer à un pager ce qui s'imprimerait normalement en rouge dans le terminal.
Quand un pipe linéaire ne suffit pas — quand on veut écrire la même sortie en plusieurs endroits, ou utiliser le résultat d'une commande comme un fichier d'entrée — Bash propose deux mécanismes complémentaires. tee est documenté avec les autres outils shell : voir tee sur la page Shell. Il sert à dupliquer un flux pour l'écrire à la fois dans un fichier et dans la suite du pipe.
<(cmd)
Présenter la sortie d'une commande comme un fichier d'entrée
Bash crée un descripteur lié à la sortie de cmd et le présente comme un nom de fichier (généralement /dev/fd/63). Permet de passer le résultat d'une commande là où une autre attend un chemin.
Syntaxe
cmd-qui-attend-un-fichier <(cmd-qui-produit)
$ diff <(sort fichier1) <(sort fichier2)
Compare les versions triées, sans avoir à créer de fichiers temporaires.
$ comm -12 <(sort a.txt) <(sort b.txt)
Liste les lignes communes aux deux fichiers (intersection).
Construit dynamiquement la liste de motifs à chercher.
Portabilité :
la substitution de processus n'est pas POSIX. Disponible en Bash, Zsh et Ksh, absente en pur sh et dash. Pour un script portable, créer un fichier temporaire avec mktemp.
Présenter l'entrée d'une commande comme un fichier de sortie
Symétrique de <(cmd) : Bash crée un descripteur sur lequel on peut écrire ; ce qu'on y écrit est branché sur stdin de la commande. Utile pour multiplier les destinations d'une sortie.
Syntaxe
cmd-qui-produit > >(cmd-qui-recoit)
$ gcc src.c 2> >(grep -E 'error|warning' >&2)
Ne conserve que les lignes contenant error ou warning sur stderr ; les autres diagnostics, le contexte et les messages localisés peuvent être perdus. Pour un diagnostic complet, conserver toute la sortie. La substitution de processus est asynchrone et son statut n’est pas celui de gcc.
Pour passer un bloc de texte ou une chaîne courte sur stdin d'une commande, sans passer par un fichier ni echo, deux constructions très lisibles.
<<EOF
Here-doc : passer un bloc de texte multi-lignes en stdin
Tout ce qui se trouve entre <<EOF et une ligne contenant exactement EOF (sans rien autour) est envoyé sur stdin de la commande. Le délimiteur est arbitraire : EOF, END, FIN, peu importe.
Variantes
<<EOF
Forme standard. $VAR et $(cmd) sont expansés dans le texte.
<<'EOF'
Le délimiteur quoted désactive l'expansion : le texte est passé tel quel.
<<-EOF
Le tiret supprime les tabulations en début de ligne — utile pour indenter le here-doc dans un script lisible.
$ ssh user@host <<'EOF'
cd /tmp
ls -la
echo "fait par $USER"
EOF
Exécute un script à distance. Le 'EOF' évite que $USER soit expansé localement avant l'envoi.
$ mysql -u admin maBase <<EOF
SELECT count(*) FROM users WHERE actif=1;
EOF
Injecte une requête multi-lignes sans créer de fichier .sql.
Forme courte du here-doc, pour quand une seule ligne suffit. La chaîne (souvent une variable) est envoyée sur stdin avec un saut de ligne ajouté. Évite la combinaison classique echo "$var" |.
Syntaxe
commande <<< "chaine ou $variable"
$ bc <<< "2 * (3 + 5)"
16
Calculatrice rapide sans echo.
$ grep -i error <<< "$ligne"
Cherche un motif dans une variable, plus concis que echo "$ligne" | grep -i error.
$ read -r mot1 mot2 <<< "alpha bravo"
Découpe une chaîne en variables, sans sous-shell (contrairement à un pipe qui isolerait les variables).
Portabilité :<<< est Bash/Zsh/Ksh, pas POSIX. En pur sh, rester sur echo "$var" | cmd ou printf '%s' "$var" | cmd.