Redirection et pipes
Les redirections des E/S permettent d’assembler des commandes en un pipeline.
1. Entrées/sorties standard
Chaque 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.
Par exemple, si le processus est un script bash, alors :
-
read linelit une ligne depuisstdin, -
echo $lineécrit une ligne surstdout, et -
echo $line >/dev/stderrécrit une ligne surstderr.
Si le processus est un script Python, alors :
-
input(line)lit une ligne depuisstdin, -
print(line)écrit une ligne surstdout, et -
print(line,file=sys.stderr)écrit une ligne surstderr.
Le processus peut ouvrir d’autres flux, pour par exemple lire ou écrire des données depuis ou dans d’autres fichiers.
2. Redirection
C’est l’opération consistant à modifier les affectations ci-dessus.
2.1. 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
$ 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
2.3. 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
2.4. Combiner les redirections
On peut mixer tout ça, afin de rediriger plusieurs flux pour un même processus :
$ 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.
$ 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,
et tout ce qui part sur /dev/null disparait.
$ 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.
$ 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 :
$ ./un_filtre <entree >sortie
On l’utilise souvent en l’intercalant dans un pipe :
$ ./premier | ./un_filtre | ./dernier
Généralement, les commandes Unix lisent leurs données au choix sur la ligne de commande, sur l’entrée standard ou depuis un fichier,
et envoyent leurs données au choix dans un fichier ou sur la sortie standard.
Par exemple pour 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
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
Lorsqu’une commande a besoin qu’on lui fournisse un nom de fichier à l’appel, alors (très souvent) on peut lui en fournir plusieurs.
$ grep root /etc/passwd /etc/group
Une commande doit accepter un nombre quelconque de fichiers pour pouvoir utiliser des noms fichier génériques :
$ grep root /etc/x* (1)
| 1 | grep reçoit ici en argument tous les noms de fichiers s’identifiant à /etc/x* |
Le traitement de la commande ci-dessus est le suivant :
-
le shell récupère la ligne
"grep root /etc/x*" -
il l’interpole, ce qui donne :
grep root /etc/x2go /etc/xdg /etc/xml /etc/xscreensaver
-
puis il lance la commande
grepen lui passant comme arguments :root /etc/x2go /etc/xdg /etc/xml /etc/xscreensaver
On voit bien que pour que cette dernière étape aboutisse,
il faut que grep accepte en argument un nombre quelconque de noms de fichiers.
4.1. L’exemple de cat
cat pour consulter le contenu de fichiers$ cat /etc/passwd /etc/group
cat pour créer un fichier$ cat > /tmp/test (1)
un
deux
trois
^D
| 1 | stdin redirigé vers le clavier,
stdout redirigé vers /tmp/test |
cat pour concaténer plusieurs fichiers$ cat /etc/passwd /etc/group > /tmp/concat
cat pour compléter un fichier$ cat >> /tmp/concat
un
deux
trois
^D
5. 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