110 votes

Comment expliquer simplement le fonctionnement des tuyaux dans Bash ?

J'utilise souvent des pipes dans Bash, par exemple :

dmesg | less

Bien que je sache ce que cela donne, il faut dmesg et me permet de la faire défiler avec less Je ne comprends pas ce qu'est la | est en train de faire. S'agit-il simplement du contraire de > ?

  • Existe-t-il une explication simple ou métaphorique à ce que l'on appelle l'état d'urgence ? | fait ?
  • Que se passe-t-il lorsque plusieurs tuyaux sont utilisés dans une même ligne ?
  • Le comportement des pipes est-il cohérent partout où il apparaît dans un script de Bash ?

129voto

quanticle Points 1527

Un pipe Unix relie le descripteur de fichier STDOUT (sortie standard) du premier processus au STDIN (entrée standard) du second. Ainsi, lorsque le premier processus écrit sur son STDOUT, cette sortie peut être immédiatement lue (à partir de STDIN) par le second processus.

L'utilisation de plusieurs tuyaux n'est pas différente de l'utilisation d'un seul tuyau. Chaque tuyau est indépendant et relie simplement les STDOUT et STDIN des processus adjacents.

Votre troisième question est un peu ambiguë. Oui, les pipes, en tant que telles, sont cohérentes partout dans un script bash. Cependant, le caractère pipe | peuvent représenter des choses différentes. Double tuyau ( || ), représente l'opérateur "ou", par exemple.

54voto

redobot Points 31

Sous Linux (et Unix en général), chaque processus dispose de trois descripteurs de fichiers par défaut :

  1. fd #0 Représente l'entrée standard du processus
  2. fd #1 Représente la sortie standard du processus
  3. fd #2 Représente la sortie d'erreur standard du processus

Normalement, lorsque vous exécutez un programme simple, ces descripteurs de fichiers sont configurés par défaut comme suit :

  1. l'entrée par défaut est lue à partir du clavier
  2. La sortie standard est configurée pour être le moniteur
  3. L'erreur standard est configurée pour être également le moniteur

Bash propose plusieurs opérateurs pour modifier ce comportement (voir les opérateurs >, >> et < par exemple). Ainsi, vous pouvez rediriger la sortie vers autre chose que la sortie standard ou lire votre entrée à partir d'un autre flux que le clavier. C'est particulièrement intéressant dans le cas où deux programmes sont collaboration de manière à ce que l'un utilise la sortie de l'autre comme entrée. Pour faciliter cette collaboration, Bash fournit l'opérateur pipe | . Veuillez noter l'utilisation de collaboration au lieu de enchaînement . J'ai évité d'utiliser ce terme car, en fait, un tuyau n'est pas séquentiel . Une ligne de commande normale avec des tuyaux présente l'aspect suivant :

    > program_1 | program_2 | ... | program_n

La ligne de commande ci-dessus est un peu trompeuse : l'utilisateur pourrait penser que le programme_2 reçoit son entrée une fois que le programme_1 a terminé son exécution, ce qui n'est pas correct. En fait, ce que fait bash est de lancer TOUS les programmes en parallèle et configure les entrées-sorties en conséquence afin que chaque programme reçoive son entrée du précédent et délivre sa sortie au suivant (dans l'ordre établi par la ligne de commande).

Voici un exemple simple de Création d'un tuyau en C de créer un tuyau entre un processus parent et un processus enfant. La partie importante est l'appel à la fonction pipe() et la façon dont le parent ferme fd 1 (côté écriture) et comment l'enfant ferme fd 1 (côté écriture). Veuillez noter que le tuyau est un unidirectionnel canal de communication. Les données ne peuvent donc circuler que dans un seul sens : fd 1 vers fd[0]. Pour plus d'informations, consultez la page de manuel de pipe().

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
    int     fd[2], nbytes;
    pid_t   childpid;
    char    string[] = "Hello, world!\n";
    char    readbuffer[80];

    pipe(fd);

    if((childpid = fork()) == -1)
    {
            perror("fork");
            exit(1);
    }

    if(childpid == 0)
    {
            /* Child process closes up input side of pipe */
            close(fd[0]);

            /* Send "string" through the output side of pipe */
            write(fd[1], string, (strlen(string)+1));
            exit(0);
    }
    else
    {
            /* Parent process closes up output side of pipe */
            close(fd[1]);

            /* Read in a string from the pipe */
            nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
            printf("Received string: %s", readbuffer);
    }

    return(0);
}

Enfin, lorsque vous avez une ligne de commande dans le formulaire :

> program_1 | program_2 | program_3

Le code de retour de l'ensemble de la ligne est fixé à la valeur dernier commande. Dans ce cas, il s'agit de program_3. Si vous souhaitez obtenir un code de retour intermédiaire, vous devez définir le paramètre queue de pipe ou l'obtenir auprès du PIPESTATUS .

20voto

Eduardo Ivanec Points 6244

Chaque processus standard sous Unix comporte au moins trois éléments descripteurs de fichiers qui sont en quelque sorte des Interfaces :

  • La sortie standard, qui est l'endroit où le processus imprime ses données (la plupart du temps la console, c'est-à-dire votre écran ou votre terminal).
  • L'entrée standard, qui est l'endroit où il obtient ses données (la plupart du temps, il s'agit de quelque chose qui s'apparente à votre clavier).
  • L'erreur standard, qui est l'endroit où les erreurs et parfois d'autres données hors bande vont. Ce n'est pas intéressant pour l'instant parce que les tuyaux ne s'en occupent pas normalement.

Le tuyau liens la sortie standard du processus de gauche vers l'entrée standard du processus de droite. Il s'agit d'un programme spécialisé qui se charge de copier tout ce qu'un programme imprime et de l'envoyer au programme suivant (celui qui se trouve après le symbole du tuyau). Ce n'est pas exactement cela, mais c'est une analogie suffisante.

Chaque tuyau fonctionne sur deux choses exactement : la sortie standard venant de sa gauche et le flux d'entrée attendu à sa droite. Chacun de ces éléments peut être attaché à un processus unique ou à une autre partie du pipeline, ce qui est le cas dans une ligne de commande multi-pipes. Mais cela n'a pas d'importance pour le fonctionnement réel du tuyau ; chaque tuyau fait le sien.

L'opérateur de redirection ( > ) fait quelque chose de similaire, mais de plus simple : par défaut, il envoie la sortie standard d'un processus directement dans un fichier. Comme vous pouvez le constater, il ne s'agit pas de l'opposé d'un pipe, mais d'un complément. Le contraire de > est sans surprise < qui prend le contenu d'un fichier et l'envoie à l'entrée standard d'un processus (imaginez un programme qui lit un fichier octet par octet et le tape dans un processus pour vous).

20voto

Dave Kerr Points 525

En résumé, il existe trois descripteurs de fichiers "spéciaux" dont il faut tenir compte. Par défaut, l'interpréteur de commandes envoie le clavier à stdin et envoie stdout y stderr à l'écran :

stdin, stdout, stderr

Un pipeline n'est qu'une commodité de l'interpréteur de commandes qui rattache l'élément stdout d'un processus directement au stdin de la suivante :

simple pipeline

Il existe de nombreuses subtilités dans le fonctionnement de ce système. stderr peut ne pas être acheminé comme prévu, comme le montre l'illustration ci-dessous :

stderr and redirection

J'ai passé pas mal de temps à essayer d'écrire une explication détaillée mais conviviale des pipelines en Bash. Le contenu complet se trouve à l'adresse suivante :

https://effective-shell.com/part-2-core-skills/thinking-in-pipelines/

7voto

Halim Qarroum Points 5758

Un pipe prend la sortie d'un processus, par sortie j'entends la sortie standard ( stdout sous UNIX) et le transmet à l'entrée standard (stdin) d'un autre processus. Ce n'est pas le contraire de la simple redirection vers la droite > dont le but est de rediriger une sortie vers une autre sortie.

Prenons par exemple la commande echo sous Linux, qui consiste simplement à imprimer sur la sortie standard une chaîne de caractères passée en paramètre. Si vous utilisez une simple redirection comme :

echo "Hello world" > helloworld.txt

l'interpréteur de commandes redirigera la sortie normale initialement prévue sur stdout et l'imprimera directement dans le fichier helloworld.txt .

Prenons maintenant l'exemple du tuyau :

ls -l | grep helloworld.txt

La sortie standard de l'application ls sera affichée à l'entrée de grep, comment cela fonctionne-t-il ?

Des programmes tels que grep lorsqu'ils sont utilisés sans arguments, lisent et attendent simplement que quelque chose leur soit transmis sur leur entrée standard (stdin) . Lorsqu'il attrape quelque chose, comme le résultat de la commande ls, grep agit normalement en trouvant une occurrence de ce que vous recherchez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X