Bash: процес заміщення і stdin


13

Наступний рядок очевидний:

echo "bla" | foo | bar

Але чи роблять ті, що нижче?

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

Хто з fooі barчитав "бла" зі stdin і чому?

Я маю на увазі, що, звичайно, я можу просто зашифрувати це і перевірити, але я не впевнений, чи це визначена поведінка, чи я використовую функції, на які не варто покладатися.

Відповіді:


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's, а trчитають інші.

З zsh, він отримує зовнішній stdin (якщо тільки це не термінал і оболонка не є інтерактивною; в цьому випадку вона перенаправлена ​​з /dev/null). ksh(там, де він виник), zshі bashє єдиними оболонками, що нагадують Борна, з підтримкою заміщення процесів AFAIK.

В echo "bla" | bar < <(foo), зауважимо , що barSTDIN «S буде труба подається на вихідний сигнал foo. Це добре визначена поведінка. У такому випадку виявляється, що foostdin - це труба, що подається echoу всіх ksh, zshі bash.

Якщо ви хочете мати послідовну поведінку в усіх трьох оболонках і бути стійким до майбутнього, оскільки поведінка може змінюватися, оскільки це не документально підтверджено, я напишу це:

echo bla | { bar <(foo); }

Щоб бути впевненим foo, stdin - це також труба echo(я не можу зрозуміти, чому ви хочете це зробити). Або:

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

Для того, щоб переконатися , що fooнічого НЕ читати з труби з echo. Або:

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

Щоб мати foostdin зовнішній stdin, як у поточних версіях zsh.


"У цьому випадку stdin foo - це труба, що подається відлунням у всіх ksh, zsh та bash." Ви перевірили це вручну тільки зараз, чи це десь задокументовано?
etam1024

Чи "в першому випадку" у першому рядку посилається на "| foo | бар` або `| бар <(foo) `?
Volker Siegel

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а весь вислів еквівалентний першому. Але це не правильно. Буває таке: Оскільки перенаправлення входу <виконується після труби ( |), вона перезаписує її . Так 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, що читає stdin і додає рядок and fooдо виводу. Цей вихід є трубопровідним cat.


І моє запитання: "Чи є факт, який awkчитає" бар ", визначеною поведінкою?"
etam1024

Так. cmd1 < <(cmd2)поводиться так само, як cmd2 | cmd1.
хаос

Або cmd1 | cmd2 | cmd3те саме, щоcmd1 | cmd3 < <(cmd2)
хаос

3
Якби це була вікіпедія, я поставив би тег "потрібне цитування" на ваші висловлювання :) Весь сенс мого питання полягає в тому, що він працює, як ви говорите, але я не міг знайти жодної документації про це.
etam1024
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.