Forum Programmation.shell Flux dans un pipe

Posté par (page perso) .
Tags : aucun
5
16
avr.
2010
Bonjour,

voila un petit comportement que je n'arrive pas à comprendre.
(echo ceci est une phrase; sleep 2 ; echo a l endroit) | rev

Cette ligne m'affiche "esarhp enu tse icec" puis attend deux secondes avant d'afficher "tiordne l a". Donc je me dit chouette rev est malin il n'attend pas d'avoir toute l'entrée pour générer la sortie (ce que je supposais).

Mais lorsque je test
(echo ceci est une phrase; sleep 2 ; echo a l endroit) | rev | rev

et bah ça attend deux secondes avant de m'afficher toute la sortie d'un coup.

J'ai fait divers tests mais je n'arrive pas à expliquer cela. Si quelqu'un a une idée du pourquoi.
  • # shell pipe est consorts

    Posté par . Évalué à 2.

    ton premier rev prend bien la sortie du shell () quand les choses sortent

    mais le 2e attend que la chaine soit envoyée par le premier rev avant de la traiter

    chez moi il suffit de ne pas mettre les () pour que cela fonctionne comme tu le souhaite
    le () ouvrant un sous shell.

    echo ceci est une phrase; sleep 2 ; echo a l endroit | rev | rev
    • [^] # Re: shell pipe est consorts

      Posté par (page perso) . Évalué à 2.

      Ha oui mais la c'est pas ce que je veux. Dans ce cas il n'y a que la chaine "a l endroit" qui passe dans rev (met 3 rev pour t'en rendre compte).
      • [^] # Re: shell pipe est consorts

        Posté par . Évalué à 2.

        ah oui tiens, j'avais pas fait attention.

        Ca vient peut-etre simplement des pipes, car tu as le meme comportement si tu chaines 2 greps, 1 grep et un rev, un rev et un grep...

        le deuxieme pipe ne pouvant probablement pas lire la sortie standard tant que la premier ne l'a pas liberé
  • # Buffer flush ...

    Posté par . Évalué à 5.

    Je suppose que dans le premier cas le shell lance le premier echo et pipe son stdout au stdin de rev. Quand le premier echo quitte, son buffer stdout est vidé et donc rev recois la chaine par stdin. Puis le shell lance de la même manière sleep et le second echo, a chaque fois qu'un programme quitte son tampon de sortie est vidée.

    Par contre, pour les deux rev, le buffer n'est vidé que quand le premier rev quitte, donc après les 2 secondes.

    Ce qui est étrange c'est que quand stdout est le terminal, un retour à la ligne est sufisant pour vider le buffer de sortie. Apparemment ce n'est pas le cas pour un pipe.
  • # C'est rev

    Posté par . Évalué à 8.

    rev, ainsi que pas mal d'utilitaires unix, ne se comporte pas de la même façon si leur sortie est redirigée ou non. Pour t'en convaincre, utilise strace :

    (echo ceci est une phrase; sleep 2 ; echo a l endroit) | strace rev

    Cela donne quelque chose comme ça, pour la sequence de lectures et d'écritures sur l'entrée/sortie standard :


    read(0, "ceci est une phrase\n", 4096) = 20
    write(1, "esarhp enu tse icec\n", 20) = 20
    read(0, "a l endroit\n", 4096) = 12
    write(1, "tiordne l a\n", 12) = 12


    Avec la redirection, ça donne ça:
    (echo ceci est une phrase; sleep 2 ; echo a l endroit) | strace rev | rev


    read(0, "ceci est une phrase\n", 4096) = 20
    read(0, "a l endroit\n", 4096) = 12
    read(0, "", 4096) = 0
    write(1, "esarhp enu tse icec\ntiordne l a\n", 32) = 32


    L'écriture n'a lieu que lorsque le programme source se ferme.

    Tout cela dans le but d'avoir un affichage ligne à ligne lorsque affiché sur ton terminal et une meilleure performance (lecture et écriture par paquet de 4Ko) sinon.
    • [^] # Re: C'est rev

      Posté par . Évalué à 5.

      Ce n'est pas un problème avec rev, mais avec la libc.
      Et en fait ce n'est pas un problème.

      La libc ne bufferise pas lorsque c'est un terminal, autrement elle bufferise (le programme doit alors faire des flush() explicites si le comportenant par défaut de la libc ne convient pas).

      La commande strace n'indique que les appels noyaux (il peut y avoir plusieurs appels à write() de la libc avant un write() du noyau).

      Pour voir les appels de rev à la libc, il faut utiliser ltrace.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.