Трубопроводи STDERR проти STDOUT


24

Відповідно до " Linux: Повна довідка 6-го видання " (стор. 44), ви можете передавати лише STDERR, використовуючи |&символи перенаправлення.

Я написав досить простий сценарій, щоб перевірити це:

#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2

Я запускаю цей сценарій так:

./script.sh |& sed 's:^:\t:'

Імовірно, відступними будуть лише рядки, надруковані на STDERR. Однак, насправді це не працює так, як я бачу:

    Normal Text.
    Error Text. 

Що я тут роблю неправильно?

Відповіді:


26

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

Якщо |&використовується, стандартна помилка command1, крім стандартного виходу, підключається до стандартного вводу command2 через трубу; це скорочення для 2>&1 |. Це неявне перенаправлення стандартної помилки на стандартний висновок виконується після будь-яких перенаправлень, визначених командою.

Отже, якщо ви не хочете змішувати стандартний вихід і стандартну помилку, вам доведеться перенаправляти стандартний висновок кудись інше. Див. Розділ Як зібрати стандартний потік помилок (stderr)?

{ ./script.sh 2>&1 >&3 | sed 's:^:\t:'; } 3>&1

Обидва fd 1 і 3 script.shта sedвказуватимуть на початкове місце stdout. Якщо ви хочете бути хорошим громадянином, можете закрити ті файли fd 3, які ці команди не потрібні:

{ ./script.sh 2>&1 >&3 3>&- | sed 's:^:\t:' 3>&-; } 3>&1

bashі ksh93може конденсувати >&3 3>&-до >&3-(fd переміщення).


Посібник з bash мені не зовсім зрозумілий. Я не зовсім розумію , чому , як чого - л ./script.sh > /tmp/stdout_goes_here |& grep 'grepping_script_stderr'не працює належним чином , тобто: редирект script.sh«s stdout(який, в відповідно до інструкції сниппет повинен відбутися перший), а потім дозволяють grepобробляти сценарію stderr. Замість цього, stderrі tdout` як в кінцевому підсумку вstdout_goes_here
sxc731

1
@ sxc731 |&є скороченим для 2>&1 |. Тож >/tmp/stdout_goes_here |&перенаправляє stdout на /tmp/stdout_goes_here, потім 2>&1перенаправляє stderr туди, куди йде stdout, який є /tmp/stdout_goes_here, і, нарешті |, не отримує жодного вводу, оскільки вихід команди був перенаправлений. Майте на увазі, що >&1перенаправлення туди, куди зараз йде дескриптор файлів , а не туди, де дескриптор 1 файлу закінчиться . Для передачі тільки stderr та перенаправлення stdout у файл є один із способів 2>&1 >/tmp/stdout_goes_here |.
Жил "ТАК - перестань бути злим"

6

|&Труби жорсткіші до stdin, як 2>&1 |, тож наступна програма отримає обидва на stdin.

$cat test.sh
#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2
$./test.sh | sed 's:^:\t:'
Error Text.
        Normal Text.
$ ./test.sh |& sed 's:^:\t:'
        Normal Text.
        Error Text.

О, значить, це в основному еквівалентно більш тривалому вираженню runcommand 2>&1 | tee? тобто runcommand |& tee?
Naftuli Kay

так, вони однакові.
Кевін

1

|&у bash - це лише (не дуже портативно) ярлик для 2>&1 |, тому ви повинні бачити кожен рядок з відступом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.