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

24

Согласно « Linux: The Complete Reference 6th Edition » (стр. 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 |&перенаправляет стандартный вывод /tmp/stdout_goes_here, затем2>&1 перенаправляет stderr туда, куда идет stdout, то есть /tmp/stdout_goes_here, и, наконец |, не получает никакого ввода, потому что выходные данные команды были перенаправлены. Имейте в виду, что >&1перенаправляет туда, куда в настоящее время направляется дескриптор файла 1 , а не туда, куда в конечном итоге придет дескриптор файла 1 . Для передачи только stderr и перенаправления stdout в файл одним из способов является 2>&1 >/tmp/stdout_goes_here |.
Жиль "ТАК - перестань быть злым"
6

|&каналы stderr к 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.
Kevin
источник
О, так это в основном эквивалентно более длинному выражению runcommand 2>&1 | tee? то есть runcommand |& tee?
Нафтули Кей
да, они одинаковы
Кевин
1

|&в bash это просто (не очень переносимый) ярлык 2>&1 |, поэтому вы должны видеть каждую строку с отступом.

jw013
источник