Pour savoir exactement ce que ça fait, il faut savoir comment fonctionne un "tube", et connaitre le principe d'entrée et de sortie standard + erreur sous Unix.
Tout processus lorsqu'il est créé possède par défaut trois descripteurs de fichiers ouverts qui lui serviront à communiquer : l'entrée standard (le clavier pour un processus interactif dans un shell), la sortie standard (le terminal par défaut), et la sortie d'erreur (le terminal également). Petit exemple : exécute la commande cat sans rien lui passer : tu verras qu'elle t'affichera tout ce que tu lui entres au clavier:
$ cat
abc
abc
def
def
ghi
ghi
Note : pour arrêter la saisie sur l'entrée standard, tu tapes sur les touches CTRL+D
En fait la commande cat est une commande qui, si on ne lui spécifie pas de paramètres, va prendre tout ce qui arrive sur l'entrée standard pour l'afficher sur la sortie standard (petite parenthèse : le nom cat vient à l'origine du mot con*cat*, et cette commande permet d'afficher sur sa sortie standard les fichiers qu'on lui passe en paramètre).
Le descripteur de fichier de l'entrée standard porte le numéro 0, celui de la sortie standard le numéro 1, et celui de la sortie d'erreur le numéro 2 (on y reviendra plus tard).
Cependant, il est possible de faire des redirections des divers périphériques par défaut. Par exemple, tu peux exécuter la commade cat < /dev/random : en exécutant cette commande tu dis à cat que l'entrée standard n'est plus le clavier, mais le fichier que tu as passé en paramètre (ici /dev/randpm génère des nombres aléatoires : tu verras une bouillie binaire s'afficher à ton écran).
De même qu'il est possible de changer le périphérique d'entrée, il est possible de changer le périphérique de sortie. Par exemple, si tu veux rediriger la sortie de la commande cat dans un fichier :
totof@superbipbip:~$ cat >/tmp/toto.txt
abc
def
ghi
la vie est belle
(taper control+d pour faire cesser la saisie)
Là tu as généré un fichier que tu peux visualiser ainsi :
totof@superbipbip:~$ more /tmp/toto.txt
abc
def
ghi
la vie est belle
totof@superbipbip:~$
Le troisième descripteur est la sortie d'erreur. Cette sortie affiche le message d'erreur. Faisons en sorte que cat génère une erreur en lui donnant un fichier bidon en paramètre d'entrée :
totof@superbipbip:~$ cat /tmp/je_nexiste_pas
cat: /tmp/je_nexiste_pas: Aucun fichier ou dossier de ce nom
Une erreur qui s'affiche à l'écran, mais tu peux également la rediriger :
La commande est "muette", mais elle génère bien un message d'erreur qu'on a redirigé vers un fichier
totof@superbipbip:~$ more /tmp/erreur.txt
cat: /tmp/je_nexiste_pas: Aucun fichier ou dossier de ce nom
Maintenant venons-en aux pipes. Quand tu enchaines les commandes via un pipe, tu demandes à ce que la sortie standard de la commande à gauche du pipe soit redirigée vers l'entrée standard de la commande à droite du pipe. Décomposons cet enchaînement :
totof@superbipbip:~$ echo "coucou" | cat
coucou
Ici, la commande écho affiche sur la sortie standard la chaîne "coucou" et la commande cat la récupère depuis son entrée standard pour l'afficher à son tour sur sa sortie standard. A noter que les deux commandes tournent en parallèle. Le traitement de la commande de droite n'attend pas que la commande de gauche soit terminée pour s'exécuter. Elles tournent ensemble et les données sont traitées par la commande de droite au fur à mesure qu'elles arrivent de la commande de gauche.
En redirigeant vers un fichier :
totof@superbipbip:~$ echo "coucou" | cat >/tmp/coucou.txt
totof@superbipbip:~$ more /tmp/coucou.txt
coucou
Si tu veux récupérer la sortie standard et la sortie d'erreur pour la rediriger vers ton pipe tu peux : il suffit de le demander. Voici ce qui se passe sans redirection :
totof@superbipbip:~$ cat /tmp/jenexistepas | cat >/tmp/coucou.txt
cat: /tmp/jenexistepas: Aucun fichier ou dossier de ce nom
Le premier cat essaie de récpérer le contenu du fichier en paramètre, mais comme il n'existe pas, le processus affiche un message d'erreur. ( et si tu vas voir le contenu de /tmp/coucou.txt, tu auras un fichier vide car la commande n'a rien retourné sur sa sortie standard).
Si on veut récupérer ce message d'erreur dans le pipe, il faut rediriger la sortie d'erreur (descripteur N° 2) vers la sortie standard (2>&1 permet de le faire dans la commande suivante) :
Là encore, à la saisie on a l'impression qui ne se passe rien .. mais si on va voir :
totof@superbipbip:~$ more /tmp/coucou.txt
cat: /tmp/jenexistepas: Aucun fichier ou dossier de ce nom
Pour résumer, quand on exécute commmande 1 | commande 2, on demande à commande 2 de récupérer sur son entrée standard le contenu du canal de sortie standard de commande 1. Et si tu veux rediriger la sortie d'erreur vers le pipe, il faut que tu précises à la commande 1 (à gauche du pipe) de rediriger sa sortie d'erreur vers la sortie standard (je précise parce que c'est facile d'oublier).
Maintenant pourquoi ce que tu as fait n'a pas fonctionné ?
tail -2 fichier.txt | nl fichier.txt
En gros tu dis à tail de récupérer les deux dernières lignes du fichier en paramètre. Tail les envoie sur sa sortie standard qui est capturée par le pipe. Sauf que à droite tu dis à la commande nl de ne pas récupérer la sortie standard, mais de récupérer les données du fichier passé en paramètre. Donc la sortie standard de la commande de gauche est ignorée. Tout ce que tu fais c'est exécuter des commandes en parallèle sans qu'elles n'interagissent entre elles.
Maintenant un petit mot : j'ai utilisé cat pour l'exemple. Cependant beaucoup de monde croit que faire un cat est nécessaire pour pouvoir ensuite le traiter par une autre commande (tu verras beaucoup de cat fichier | grep par exemple). Le cat ne sert à rien dans ce cas. Démonstration avec le fichier généré précédemment :
totof@superbipbip:~$ more /tmp/toto.txt
abc
def
ghi
la vie est belle
# Qu'est-ce qu'un pipe ?
Posté par totof2000 . En réponse au message Incompréhension des pipes sur Linux. Évalué à 10. Dernière modification le 26 août 2024 à 23:44.
Pour savoir exactement ce que ça fait, il faut savoir comment fonctionne un "tube", et connaitre le principe d'entrée et de sortie standard + erreur sous Unix.
Tout processus lorsqu'il est créé possède par défaut trois descripteurs de fichiers ouverts qui lui serviront à communiquer : l'entrée standard (le clavier pour un processus interactif dans un shell), la sortie standard (le terminal par défaut), et la sortie d'erreur (le terminal également). Petit exemple : exécute la commande cat sans rien lui passer : tu verras qu'elle t'affichera tout ce que tu lui entres au clavier:
Note : pour arrêter la saisie sur l'entrée standard, tu tapes sur les touches CTRL+D
En fait la commande cat est une commande qui, si on ne lui spécifie pas de paramètres, va prendre tout ce qui arrive sur l'entrée standard pour l'afficher sur la sortie standard (petite parenthèse : le nom cat vient à l'origine du mot con*cat*, et cette commande permet d'afficher sur sa sortie standard les fichiers qu'on lui passe en paramètre).
Le descripteur de fichier de l'entrée standard porte le numéro 0, celui de la sortie standard le numéro 1, et celui de la sortie d'erreur le numéro 2 (on y reviendra plus tard).
Cependant, il est possible de faire des redirections des divers périphériques par défaut. Par exemple, tu peux exécuter la commade cat < /dev/random : en exécutant cette commande tu dis à cat que l'entrée standard n'est plus le clavier, mais le fichier que tu as passé en paramètre (ici /dev/randpm génère des nombres aléatoires : tu verras une bouillie binaire s'afficher à ton écran).
De même qu'il est possible de changer le périphérique d'entrée, il est possible de changer le périphérique de sortie. Par exemple, si tu veux rediriger la sortie de la commande cat dans un fichier :
(taper control+d pour faire cesser la saisie)
Là tu as généré un fichier que tu peux visualiser ainsi :
Le troisième descripteur est la sortie d'erreur. Cette sortie affiche le message d'erreur. Faisons en sorte que cat génère une erreur en lui donnant un fichier bidon en paramètre d'entrée :
Une erreur qui s'affiche à l'écran, mais tu peux également la rediriger :
La commande est "muette", mais elle génère bien un message d'erreur qu'on a redirigé vers un fichier
Maintenant venons-en aux pipes. Quand tu enchaines les commandes via un pipe, tu demandes à ce que la sortie standard de la commande à gauche du pipe soit redirigée vers l'entrée standard de la commande à droite du pipe. Décomposons cet enchaînement :
Ici, la commande écho affiche sur la sortie standard la chaîne "coucou" et la commande cat la récupère depuis son entrée standard pour l'afficher à son tour sur sa sortie standard. A noter que les deux commandes tournent en parallèle. Le traitement de la commande de droite n'attend pas que la commande de gauche soit terminée pour s'exécuter. Elles tournent ensemble et les données sont traitées par la commande de droite au fur à mesure qu'elles arrivent de la commande de gauche.
En redirigeant vers un fichier :
Si tu veux récupérer la sortie standard et la sortie d'erreur pour la rediriger vers ton pipe tu peux : il suffit de le demander. Voici ce qui se passe sans redirection :
Le premier cat essaie de récpérer le contenu du fichier en paramètre, mais comme il n'existe pas, le processus affiche un message d'erreur. ( et si tu vas voir le contenu de /tmp/coucou.txt, tu auras un fichier vide car la commande n'a rien retourné sur sa sortie standard).
Si on veut récupérer ce message d'erreur dans le pipe, il faut rediriger la sortie d'erreur (descripteur N° 2) vers la sortie standard (2>&1 permet de le faire dans la commande suivante) :
Là encore, à la saisie on a l'impression qui ne se passe rien .. mais si on va voir :
Pour résumer, quand on exécute commmande 1 | commande 2, on demande à commande 2 de récupérer sur son entrée standard le contenu du canal de sortie standard de commande 1. Et si tu veux rediriger la sortie d'erreur vers le pipe, il faut que tu précises à la commande 1 (à gauche du pipe) de rediriger sa sortie d'erreur vers la sortie standard (je précise parce que c'est facile d'oublier).
Maintenant pourquoi ce que tu as fait n'a pas fonctionné ?
En gros tu dis à tail de récupérer les deux dernières lignes du fichier en paramètre. Tail les envoie sur sa sortie standard qui est capturée par le pipe. Sauf que à droite tu dis à la commande nl de ne pas récupérer la sortie standard, mais de récupérer les données du fichier passé en paramètre. Donc la sortie standard de la commande de gauche est ignorée. Tout ce que tu fais c'est exécuter des commandes en parallèle sans qu'elles n'interagissent entre elles.
Maintenant un petit mot : j'ai utilisé cat pour l'exemple. Cependant beaucoup de monde croit que faire un cat est nécessaire pour pouvoir ensuite le traiter par une autre commande (tu verras beaucoup de cat fichier | grep par exemple). Le cat ne sert à rien dans ce cas. Démonstration avec le fichier généré précédemment :
Beaucoup de gens vont faire ceci :
Le cat ne sert à rien. On appelle ça UUOC ou Useless use of cat. Dans ce cas il vaut mieux faire ceci:
Et si ta commande ne prend pas de fichier en paramètre mais ne prend ses données sur l'entrée standard (oui ça existe) :