Bash: substitution de processus et stdin

13

La ligne suivante est évidente:

echo "bla" | foo | bar

Mais ceux ci-dessous font-ils de même?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

Lequel des fooet barlire "bla" de stdin et pourquoi?

Je veux dire que, bien sûr, je peux simplement le coder et le vérifier, mais je ne sais pas si c'est un comportement défini ou j'exploite des fonctionnalités sur lesquelles je ne devrais pas compter.

etam1024
la source

Réponses:

9

C'est AFAICS dépendant du shell et non documenté. Dans kshet bash, dans le premier cas, foopartagera le même stdin que bar. Ils se battront pour la sortie de echo.

Ainsi, par exemple,

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

Vous voyez des preuves qui pastelisent tous les autres blocs de texte à partir de seqla sortie de tout en trlisant les autres.

Avec zsh, il obtient le stdin externe (sauf s'il s'agit d'un terminal et que le shell n'est pas interactif auquel cas il est redirigé depuis /dev/null). ksh(d'où il provient), zshet bashsont les seuls coquilles de type Bourne avec prise en charge de la substitution de processus AFAIK.

Dans echo "bla" | bar < <(foo) , notez que c'est barstdin qui sera le tuyau alimenté par la sortie de foo. C'est un comportement bien défini. Dans ce cas, il apparaît que foostdin est le tuyau alimenté par echodans tous ksh, zshet bash.

Si vous voulez avoir un comportement cohérent entre les trois shells et être à l'épreuve du temps puisque le comportement peut changer car il n'est pas documenté, je l'écrirais:

echo bla | { bar <(foo); }

Pour être sûr que foostdin est aussi le tuyau de echo(je ne vois pas pourquoi vous voudriez faire ça cependant). Ou:

echo bla | bar <(foo < /dev/null)

Assurer foo ne pas lire le tuyau de echo. Ou:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

Avoir foo stdin le stdin externe comme dans les versions actuelles de zsh.

Stéphane Chazelas
la source
"Dans ce cas, le stdin de foo est le tuyau alimenté par l'écho dans tous les ksh, zsh et bash." Vous venez de tester cela à la main, ou est-ce quelque part documenté?
etam1024
Est-ce que "dans le premier cas" dans la première ligne fait référence à `| foo | bar` ou `| bar <(foo) `?
Volker Siegel
4

echo "bla" | foo | bar: La sortie de echo "bla" est redirigée vers foo, dont la sortie est redirigée vers bar.

echo "bla" | bar <(foo): Celui-là dirige la sortie de echo "bla"vers bar. Mais barest exécuté avec un argument. L'argument est le chemin d'accès au fichier descripteur, où la sortie de foosera envoyée. Cet argument se comporte comme un fichier contenant la sortie de foo. Ce n'est donc pas pareil.

echo "bla" | bar < <(foo): On peut supposer que la sortie de echo "bla"doit être envoyée à baret la déclaration entière est équivalente à la première. Mais ce n'est pas correct. Il se produit ce qui suit: Étant donné que la redirection d'entrée <est effectuée après le tube ( |), il l'écrase . Il echo "bla"n'est donc pas question de barrer. Au lieu de cela, la sortie de fooest redirigée en tant qu'entrée standard vers bar. Pour effacer cela, consultez la commande et la sortie suivantes:

$ echo "bla" | cat < <(echo "foo")
foo

Comme vous le voyez, echo "bla"est remplacé par echo "foo".

Maintenant, voyez cette commande:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

So echo "bar"est canalisé vers awk, qui lit stdin et ajoute la chaîne and fooà la sortie. Cette sortie est dirigée vers cat.

le chaos
la source
Et ma question est: "Est-ce que le fait de awklire" bar "est un comportement défini?"
etam1024
Oui, ça l'est. cmd1 < <(cmd2)se comporte de la même manière que cmd2 | cmd1.
chaos
Ou cmd1 | cmd2 | cmd3est le même quecmd1 | cmd3 < <(cmd2)
chaos
3
Si c'était wikipedia, je mettrais la balise "citation nécessaire" sur vos déclarations :) L'intérêt de ma question est que cela fonctionne comme vous le dites, mais je n'ai trouvé aucune documentation à ce sujet.
etam1024