dernière modification : 2025

Redirection et pipes

Les redirections des E/S permettent d’assembler des processus en pipeline.

1. Entrées/sorties standard

De base, tout processus dispose de 3 flux de communication :

  • 1 flux d’entrée stdin (descripteur 0) pour l’acquisition de données, affecté par défaut au clavier,

  • 2 flux de sortie : stdout (descripteur 1) pour la sortie des résultats, et stderr (descripteur 2) pour l’envoi des messages d’erreur, tous deux affectés par défaut à l’écran.

redirect1

Ainsi :

  • read line lit une ligne depuis stdin,

  • echo $line écrit une ligne sur stdout, et

  • echo $line >/dev/stderr écrit une ligne sur stderr.

Un processus peut ouvrir d’autres flux, en plus de ces 3 flux parv défaut, pour par exemple lire ou écrire des données depuis ou dans des fichiers.

Par exemple, en exécutant :

$ find / -type d -name lib
find: ‘/boot/efi’: Permission non accordée
find: ‘/boot/grub2’: Permission non accordée
/tmp/lib

on constate que find sort 2 types de messages :

  • ceux correspondant aux répertoires trouvés

  • ceux correspondant aux interdictions

2. Redirection

C’est l’opération consistant à modifier les affectations ci-dessus.

2.1. Redirection de l’entrée standard

redirect2
exemples de redirection de l’entrée standard
$ less < /etc/passwd
$ read line < /etc/passwd
$ echo $line
root:x:0:0:root:/root:/bin/bash

2.2. Redirection de la sortie standard

redirect3
exemple redirection de la sortie standard
$ ls > /tmp/ls.out        # écrase /tmp/ls.out s'il existait
$ ls / >> /tmp/ls.out     # ajoute à la fin de /tmp/ls.out s'il existe, le crée sinon
$ find / -type d -name lib > /dev/null
find: ‘/boot/efi’: Permission non accordée
find: ‘/boot/grub2’: Permission non accordée

2.3. Redirection de la sortie d’erreur standard

redirect4
exemple redirection de la sortie d’erreur standard
$ grep -R unix /etc 2>/tmp/grep.err        # écrase /tmp/grep.err s'il existait
$ grep -R unix /etc 2>>/tmp/grep.err       # n'écrase pas /tmp/grep.err s'il existait
$ find / -type d -name lib 2>/dev/null
/tmp/lib

2.4. Combiner les redirections

On peut mixer tout ça, afin de rediriger plusieurs flux pour un même processus :

redirect5
exemple
$ grep -R unix /etc >/tmp/grep.out 2>/tmp/grep.err  # redirige [1] et [2]
$ grep bin < /etc/passwd > /tmp/bin.lines           # redirige [0] et [1]

2.5. Autres possibilités

D’autres redirections sont possibles, comme rediriger stderr vers stdout.

redirect6
exemple
$ grep -R unix /etc >/tmp/grep.out 2>&1

2.6. /dev/tty et /dev/null

Ce sont 2 fichiers périphériques particuliers :

$ ls -l /dev/null /dev/tty
crw-rw-rw-. 1 root root 1, 3 27 déc.  09:51 /dev/null
crw-rw-rw-. 1 root tty  5, 0 27 déc.  09:51 /dev/tty

/dev/tty correspond à la console courante. Lire depuis le fichier /dev/tty revient à lire sur le clavier. Ecrire sur /dev/tty revient à écrire sur l’écran.

Exemple d’utilisation : dans une commande dont la sortie a été redirigée vers un fichier, vouloir malgré tout écrire sur l’écran

/dev/null est un trou noir. Lire sur /dev/null renvoie aussitôt une fin de fichier. De même, tout ce qui part sur /dev/null est perdu.

/dev/null est souvent utilisé pour faire disparaitre des information non souhaitées :
$ grep -il linux /etc/* 2>/dev/null

3. Pipe

C’est une chaîne de processus dont les flux d’E/S sont interconnectés 2 à 2.

pipe1
$ ps aux | grep $USER | less
$ ps aux | grep $USER > /tmp/ps.out

4. Filtres

Un filtre est une commande destinée à agir sur le flux de données qui la traverse. Les données arrivent sur stdin et ressortent modifiées sur stdout :

schéma d’utilisation d’un filtre
$ ./un_filtre <entree >sortie

Il s’intercale dans un pipe :

filtre dans un pipe
$ ./premier | ./un_filtre | ./dernier

La plupart des commandes Unix lisent leurs données au choix sur l’entrée standard ou depuis un fichier.

Exemple de la commande less : si on lui fournit un argument, alors less le considère comme le nom d’un fichier à visualiser, et s’il n’y a pas d’argument, alors less visualise ce qui lui arrive sur stdin :

$ less /etc/passwd        # données lues depuis un fichier
$ less < /etc/passwd      # données lues depuis stdin
$ ls -l | less            # données lues depuis stdin

Donc souvent, les commandes Unix se comportent comme un filtre lorsqu’on ne leur fournit pas le nom de fichier qu’elles attendent. Exemple :

$ grep root /etc/passwd        # grep lisant ses données depuis un fichier
$ ps aux | grep $USER | less   # grep utilisé comme filtre

5. Commandes anodines

Les commandes historiques d’Unix sont souvent simples. Elles suivent généralement le principe suivant : faire une chose précise, sans chercher à en faire tropDo one thing and do it well »).

Voici donc quelques commandes anodines de manipulation de texte. Malgré leur simplicité apparente, elle peuvent s’avèrer extrêmement utiles lorsqu’on les combine entre elles.

5.1. L’exemple de cat

cat est l’une des commandes les plus simples qu’il soit.

consulter le contenu d’un fichier

$ cat /etc/passwd

consulter le contenu de plusieurs fichiers

$ cat /etc/passwd /etc/group

concaténer plusieurs fichiers

Par conséquent, on peut l’utiliser pour concaténer plusieurs fichiers (d’où son nom) :

$ cat /etc/passwd /etc/group > /tmp/concat

Si on ne lui fournit pas d’argument, alors elle recopie sur sa sortie standard ce qui arrive sur son entrée stanbdard. C’est une fonctionnalité vraiment toute bête. Mais cela permet de remplir un fichier à partir du clavier sans utiliser un éditeur de texte :

créer un fichier

$ cat > /tmp/test (1)
un
deux
trois
^D
1 stdin affecté au clavier, stdout redirigé vers /tmp/test

ou de le compléter :

compléter un fichier

$ cat >> /tmp/concat
un
deux
trois
^D

numéroter les lignes

$ cat -n /etc/services
$ ls | cat -n

5.2. wc

wc (word count) renvoie le nombres de caractères, de mots et de lignes d’un flux. C’est un filtre utile pour compter. Par exemple, combien y a-t-il de fichiers dans son homedir :

$ find ~ -type f | wc -l

5.3. more - less

more est la commande historique, less en est une amélioration. Ces 2 commandes paginent un flux.

$ ps -edf | less

5.4. grep

grep filtre les lignes d’un flux. grep s’intercale fréquemment dans un pipe pour éliminer des lignes :

$ ps -edf | grep $USER | less

5.5. awk

awk est l’exception de cette liste, car elle n’est pas anodine, c’est une puissante commande de traitement de texte. Aujourd’hui, elle n’est plus indispensable (awk est le précurseur du langage Perl qui l’a supplanté), mais sa faculté à découper une ligne de texte la rend encore utile au quotidien.

$ ps aux | awk '{print $1,$2,$11}'
USER PID COMMAND
root 1 /usr/lib/systemd/systemd
root 980 /usr/lib/systemd/systemd-journald
root 1019 /usr/lib/systemd/systemd-nsresourced
root 1020 /usr/lib/systemd/systemd-userdbd
root 1036 /usr/lib/systemd/systemd-udevd
rpc 1226 /usr/bin/rpcbind
systemd+ 1234 /usr/lib/systemd/systemd-oomd
systemd+ 1236 /usr/lib/systemd/systemd-resolved
$ awk -F : '{print $1," -> ",$5}' /etc/passwd
root  ->  Super User
bin  ->  bin
daemon  ->  daemon
adm  ->  adm
lp  ->  lp
sync  ->  sync
shutdown  ->  shutdown
halt  ->  halt
mail  ->  mail
operator  ->  operator
games  ->  games
ftp  ->  FTP User
nobody  ->  Kernel Overflow User

5.6. sort

sort trie les lignes d’un flux (par ordre alphabétique par défaut) :

$ sort /etc/passwd | head -7
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/usr/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
backuppc:x:976:976::/var/lib/BackupPC:/sbin/nologin
bin:x:1:1:bin:/bin:/usr/sbin/nologin
chrony:x:997:995:chrony system user:/var/lib/chrony:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/usr/sbin/nologin

Par exemple, avoir la liste de ses répertoires personnels par taille décroissante :

$ du -d1 ~ | sort -rn
14269060        /home/jaclin
11658832        /home/jaclin/Documents
219080          /home/jaclin/.mozilla
192776          /home/jaclin/.local
61424           /home/jaclin/Téléchargements
24784           /home/jaclin/tmp
2944            /home/jaclin/Images
56              /home/jaclin/bin
32              /home/jaclin/.ssh
24              /home/jaclin/.bashrc.d
4               /home/jaclin/Desktop
0               /home/jaclin/Vidéos

ou avec des tailles plus parlante :

$ du -hd1 ~ | sort -rh
14G     /home/jaclin
12G     /home/jaclin/Documents
214M    /home/jaclin/.mozilla
189M    /home/jaclin/.local
60M     /home/jaclin/Téléchargements
25M     /home/jaclin/tmp
2,9M    /home/jaclin/Images
56K     /home/jaclin/bin
32K     /home/jaclin/.ssh
24K     /home/jaclin/.bashrc.d
4,0K    /home/jaclin/Desktop
0       /home/jaclin/Vidéos

5.7. uniq

uniq garde 1 seul exemplaire d’une suite de lignes consécutives identiques (et peut compter les exemplaires regroupés).

Par exemple :

$ cat  f
un
un
deux
un
trois
trois
trois
trois
deux
deux

$ cat f | uniq -c
2 un
1 deux
1 un
4 trois
2 deux

Par exemple, sortir la liste des utilisateurs associés à leur nombre de processus, triée par nombre de processus :

$ ps aux | sort | awk '{print $1}' | uniq -c | sort -n
      1 chrony
      1 colord
      1 geoclue
      1 polkitd
      1 rtkit
      1 USER
      2 avahi
      2 dbus
      2 postfix
      2 systemd+
    120 jaclin
    265 root

5.8. tail - head

Extrait les dernières/premières lignes d’un flux.

les 10 premiers mots contenant baba
$ grep baba /usr/share/dict/words | head
Ababa
baba
babacoote
babai
babajaga
baba-koto
babakoto
babas
babasco
babassu
les 10 derniers mots contenant baba
$ grep baba /usr/share/dict/words | tail
babasco
babassu
babassus
babasu
babaylan
babaylanes
Barbabas
Cayubaba
Cayubaban
Mbabane
les 3 plus gros répertoires
$ du -h ~ | sort -h | tail -3
367M    /home/jaclin/.config
12G     /home/jaclin/Documents
14G     /home/jaclin

A noter l’option -f de tail, qui lui permet de rester en attente d’arrivée de nouvelles lignes dans le ou les fichiers spécifiés. Très utile pour surveiller les logs.

$ tail -f /var/log/messages

5.9. tee

tee est un dupliqueur de flux. Les données issues de stdin ressortent de tee à la fois sur stdout et dans les fichiers dont les noms lui sont donnés.

tee
$ find /usr -name '*lib*' | tee /tmp/find.out | less

6. Heredoc

C’est une construction syntaxique permettant d’envoyer des lignes de texte sur stdin, sans créer de fichier :

$ ssh data << EOT
whoami
hostname
pwd
EOT

Cette écriture est pratique dans un script, car elle évite de créer un fichier de données à part. La commande ci-dessus est équivalente aux 2 commandes ci-dessous :

$ cat > /tmp/cmd
whoami
hostname
pwd
^D

$ ssh data < /tmp/cmd

7. Conclusion

Les commandes Unix sont généralement minimalistes, mais pensées pour coopérer. Les composer via les pipes permet de réaliser des traitements sophistiqués. Elles sont simples par conception, spécialisées par fonction, et puissantes par composition.