blocage / non-blocage de canalisations / redirige la substitution de command à l'intérieur

J'ai observé le comportement suivant dans bash:

{ echo 'foo' ; sleep 10 ; } 

-> sortie standard "foo" apparaît immédiatement, après 10 secondes la command est terminée (comme prévu)

 { echo 'foo' ; sleep 10 ; } > >(grep 'oo') 

-> sortie standard "foo" apparaît immédiatement, après 10 secondes la command est terminée (comme prévu)

 { echo 'foo' ; sleep 10 ; } > >(grep 'oo' | grep 'oo') 

-> sortie standard "foo" apparaît après 10 secondes

 { echo 'foo' ; sleep 10 ; } > >(grep 'oo' >&2) 

-> erreur standard "foo" apparaît après 10 secondes

Pourquoi la command line avec le seul grep dans la substitution de command affiche-t-elle son résultat immédiatement alors que les variantes avec le canal et la redirection attendent la fin du sumil?

Vous n'avez pas besoin d'avoir autant de fantaisie; vous pouvez observer le même effet avec

 { echo 'foo' ; sleep 10 ; } | grep oo | grep oo 

ou

 { echo 'foo' ; sleep 10 ; } | grep oo | cat 

ou

  • Ouvrez deux terminaux. Accédez au même directory dans les deux (par exemple, votre directory personnel, ou /tmp ).
  • Dans l'un, faire { echo 'foo' ; sleep 10 ; } | grep oo > foo.out { echo 'foo' ; sleep 10 ; } | grep oo > foo.out { echo 'foo' ; sleep 10 ; } | grep oo > foo.out .
  • Dans l'autre cas, ls -ld foo.out plusieurs fois.
    Vous verrez que le file foo.out apparaît immédiatement, mais qu'il est de taille 0 pendant dix secondes, après quoi il devient 4 octets.

Simplement: les tests grep pour voir si sa sortie (standard) est un terminal. Si c'est le cas, il écrit la sortie aussi rapidement que la sortie à écrire. Si ce n'est pas le cas, il tamponne sa sortie et écrit N octets à la fois, où N est typiquement 512, mais peut être différent dans certaines implémentations.

Extension de la réponse de Scott:

Comparer

  { echo 'foo' ; sleep 3 ; } | grep oo | cat 

avec

  { echo 'foo' ; sleep 3 ; } | stdbuf -o 0 grep oo | cat