Bash: процесс подстановки и ввода

13

Следующая строка очевидна:

echo "bla" | foo | bar

Но приведенные ниже делают то же самое?

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

Что из того fooи barчитать "бла" из stdin и почему?

Я имею в виду, что, конечно, я могу просто написать код и проверить его, но я не уверен, определено ли это поведение или я использую функции, на которые не следует полагаться.

etam1024
источник

Ответы:

9

Это зависит от оболочки и не документировано AFAICS. В kshи bash, в первом случае, fooбудет использоваться тот же stdin, что и bar. Они будут бороться за выход echo.

Так, например, в

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

Вы видите свидетельство, которое pasteчитает каждый второй блок текста из seqвыходных данных, в то время как trчитает другие.

С помощью zshон получает внешний stdin (если только он не является терминалом и оболочка не является интерактивной, и в этом случае она перенаправляется /dev/null). ksh(где он возник), zshи bashявляются единственными Bourne-подобными оболочками с поддержкой процесса замены AFAIK.

В echo "bla" | bar < <(foo), заметим , что barSTDIN «S будет труба подается на выходной сигнал foo. Это хорошо определенное поведение. В этом случае, похоже, что foostdin - это канал, которым питаются echoвсе ksh, zshи bash.

Если вы хотите иметь согласованное поведение во всех трех оболочках и быть ориентированными на будущее, поскольку поведение может измениться, поскольку оно не задокументировано, я написал бы это:

echo bla | { bar <(foo); }

Чтобы быть уверенным, что foostdin - это еще и канал echo(хотя я не понимаю, почему вы хотите это сделать). Или:

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

Для того, чтобы убедиться , что fooничего не читать из трубы с echo. Или:

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

Иметь foo's stdin' внешний stdin, как в текущих версиях zsh.

Стефан Шазелас
источник
«В этом случае stdin foo - это канал, передаваемый echo во всех ksh, zsh и bash». Вы проверяли это вручную только сейчас, или это где-то задокументировано?
etam1024
Относится ли «в первом случае» в первой строке к `| фу | bar` или `| bar <(foo) `?
Фолькер Сигел
4

echo "bla" | foo | bar: Выход echo "bla"перенаправлен на foo, чей выход перенаправлен на bar.

echo "bla" | bar <(foo)Тот, кто передает вывод echo "bla"в bar. Но barвыполняется с аргументом. Аргумент - это путь к дескриптору файла, куда fooбудет отправлен вывод . Этот аргумент ведет себя как файл, который содержит выходные данные foo. Так что это не то же самое.

echo "bla" | bar < <(foo): Можно предположить, что выходные данные echo "bla"должны быть отправлены, barи весь оператор эквивалентен первому. Но это не правильно. Происходит следующее: поскольку перенаправление ввода <выполняется после pipe ( |), оно перезаписывает его . Так echo "bla"что не пускай в бар. Вместо этого вывод fooперенаправляется как стандартный ввод в bar. Чтобы очистить это, смотрите следующую команду и вывод:

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

Как видите echo "bla", вытесняется echo "foo".

Теперь посмотрим на эту команду:

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

Так echo "bar"что по каналу awk, который читает стандартный ввод и добавляет строкуand foo к выводу. Этот вывод передается по каналу cat.

хаос
источник
И мой вопрос: «Является ли тот факт, что awkчитает« бар »определенное поведение?»
etam1024
Да, это так. cmd1 < <(cmd2)ведет себя так же, как cmd2 | cmd1.
хаос
Или так cmd1 | cmd2 | cmd3же, какcmd1 | cmd3 < <(cmd2)
хаос
3
Если бы это была википедия, я бы поставил тег «цитата нужна» в ваших высказываниях :) Суть моего вопроса в том, что он работает, как вы говорите, но я не смог найти никакой документации по этому поводу.
etam1024