web-dev-qa-db-fra.com

Quelle est une explication simple du fonctionnement des tuyaux dans Bash?

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

dmesg | less

Bien que je sache ce que cela produit, cela prend dmesg et me permet de le faire défiler avec less, je ne comprends pas ce que le | fait. Est-ce simplement le contraire de >?

  • Existe-t-il une explication simple ou métaphorique de ce que | Est-ce que?
  • Que se passe-t-il lorsque plusieurs tuyaux sont utilisés sur une même ligne?
  • Le comportement des tuyaux est-il cohérent partout où il apparaît dans un script Bash?
55
Village

Un tube Unix relie le descripteur de fichier STDOUT (sortie standard) du premier processus au STDIN (entrée standard) du second. Ce qui se produit alors, c'est que lorsque le premier processus écrit dans son STDOUT, cette sortie peut être immédiatement lue (depuis 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 le STDOUT et le STDIN des processus adjacents.

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

68
quanticle

Sous Linux (et Unix en général), chaque processus a trois descripteurs de fichier 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 par défaut sont configurés 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 fournit plusieurs opérateurs pour changer ce comportement (jetez un œil aux 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 différent du clavier. Particulièrement intéressant le cas où deux programmes sont collaborent de telle manière que l'un utilise la sortie de l'autre comme entrée. Pour faciliter cette collaboration, Bash fournit à l'opérateur de tuyau |. Veuillez noter l'utilisation de la collaboration au lieu de chaînage. J'ai évité d'utiliser ce terme car en fait un pipe n'est pas séquentiel . Une ligne de commande normale avec des tuyaux a l'aspect suivant:

    > program_1 | program_2 | ... | program_n

La ligne de commande ci-dessus est un peu trompeuse: l'utilisateur pourrait penser que program_2 obtient son entrée une fois que le programme_1 a terminé son exécution, ce qui n'est pas correct. En fait, ce que bash fait est de lancer [~ # ~] tous [~ # ~] les programmes en parallèle et il configure les sorties entrées en conséquence donc chaque programme obtient son entrée du précédent et délivre sa sortie au suivant (dans l'ordre établi en ligne de commande).

Voici un exemple simple de Création d'un tuyau en C de création d'un tuyau entre un processus parent et enfant. La partie importante est l'appel à la pipe () et comment 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 canal de communication unidirectionnel . Ainsi, les données ne peuvent circuler que dans une seule direction: 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 et surtout, lorsque vous avez une ligne de commande sous la forme:

> program_1 | program_2 | program_3

Le code retour de la ligne entière est défini sur la commande last . Dans ce cas, program_3. Si vous souhaitez obtenir un code retour intermédiaire, vous devez définir le pipefail ou l'obtenir à partir du [~ # ~] pipestatus [~ # ~] .

20
rkachach

Chaque processus standard sous Unix a au moins trois descripteurs de fichiers, qui sont un peu comme interfaces:

  • 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 d'où proviennent ses données (la plupart du temps, il peut s'agir de quelque chose qui ressemble à votre clavier).
  • Erreur standard, qui est l'endroit où les erreurs et parfois d'autres données hors bande disparaissent. Ce n'est pas intéressant pour le moment car les tuyaux ne le gèrent pas normalement.

Le tuyau connecte la sortie standard du processus à gauche à l'entrée standard du processus à droite. Vous pouvez le considérer comme un programme dédié qui se charge de copier tout ce qu'un programme imprime et de le transmettre au programme suivant (celui après le symbole du tuyau). Ce n'est pas exactement cela, mais c'est une analogie suffisamment adéquate.

Chaque tube fonctionne sur exactement deux choses: la sortie standard venant de sa gauche et le flux d'entrée attendu à sa droite. Chacun de ceux-ci pourrait être attaché à un seul processus ou à un autre bit du pipeline, ce qui est le cas dans une ligne de commande multi-tubes. Mais cela n'est pas pertinent pour le fonctionnement réel du tuyau; chaque pipe fait la sienne.

L'opérateur de redirection (>) fait quelque chose de connexe, mais plus simple: par défaut, il envoie la sortie standard d'un processus directement dans un fichier. Comme vous pouvez le voir, ce n'est pas le contraire d'un tuyau, mais en fait complémentaire. L'opposé de > est sans surprise <, qui prend le contenu d'un fichier et l'envoie à l'entrée standard d'un processus (pensez-y comme un programme qui lit un fichier octet par octet et le tape dans un processus pour vous).

15
Eduardo Ivanec

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

Par exemple, prenez la commande echo sous Linux qui affiche simplement une chaîne passée en paramètre sur la sortie standard. Si vous utilisez une simple redirection comme:

echo "Hello world" > helloworld.txt

le Shell redirigera la sortie normale initialement prévue pour être sur stdout et l'imprimera directement dans le fichier helloworld.txt.

Maintenant, prenez cet exemple qui implique le tuyau:

ls -l | grep helloworld.txt

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

Des programmes tels que grep lorsqu'ils sont utilisés sans aucun argument lisent et attendent simplement que quelque chose soit transmis sur leur entrée standard (stdin). Quand ils attrapent quelque chose, comme la sortie de la commande ls, grep agit normalement en trouvant une occurrence de ce que vous recherchez.

6
Halim Qarroum

L'opérateur de pipe prend la sortie de la première commande et la "pipe" à la seconde en connectant stdin et stdout. Dans votre exemple, au lieu que la sortie de la commande dmesg passe à stdout (et la lance sur la console), elle va directement dans votre prochaine commande.

2
franka

Les tuyaux sont très simples comme ça.

Vous avez la sortie d'une commande. Vous pouvez fournir cette sortie comme entrée dans une autre commande à l'aide de pipe. Vous pouvez diriger autant de commandes que vous le souhaitez.

ex: ls | grep my | fichiers grep

Cela répertorie d'abord les fichiers dans le répertoire de travail. Cette sortie est vérifiée par la commande grep pour le mot "my". La sortie de ceci est maintenant dans la deuxième commande grep qui recherche finalement les "fichiers" Word. C'est ça.

2
Xander
  • | place le STDOUT de la commande à gauche sur le STDIN de la commande à droite.

  • Si vous utilisez plusieurs tuyaux, ce n'est qu'une chaîne de tuyaux. La première sortie de commandes est définie sur la deuxième entrée de commandes. La deuxième sortie de commandes est définie sur la prochaine entrée de commandes. Un Ainsi de suite.

  • Il est disponible dans tous les interpréteurs de commandes basés sur Linux/widows.

2
Shiplu Mokaddim

Si vous traitez chaque commande unix comme un module autonome,
mais vous en avez besoin pour vous parler en utilisant le texte comme une interface cohérente,
Comment ceci peut être fait?

cmd                       input                    output

echo "foobar"             string                   "foobar" 
cat "somefile.txt"        file                     *string inside the file*
grep "pattern" "a.txt"    pattern, input file      *matched string*

Tu peux dire | est une métaphore pour passer le relais dans un marathon à relais.
Sa même forme comme un!
cat -> echo -> less -> awk -> Perl est analogue à cat | echo | less | awk | Perl.

cat "somefile.txt" | echo
cat passe sa sortie pour que echo l'utilise.

Que se passe-t-il lorsqu'il y a plus d'une entrée?
cat "somefile.txt" | grep "pattern"
Il existe une règle implicite qui dit "passez-le en tant que fichier d'entrée plutôt que modèle "pour grep.
Vous développerez lentement l'œil pour savoir quel paramètre est lequel par expérience.

1
cctan