Как трубу stderr без трубопровода stdout

24

Как передать стандартный поток ошибок, не передавая стандартный поток вывода?

Я знаю, что эта команда работает, но она также записывает стандарт.

Command 2>&1 | tee -a $LOG

Как получить только стандартную ошибку?

Примечание. Из этого я хочу просто записать поток stderr в журнал и записать как stderr, так и stdout в консоль.

Пересекать
источник

Ответы:

26

Для этого используйте один дополнительный файловый дескриптор для переключения stderr и stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

В принципе, это работает, или, по крайней мере, я думаю, что это работает следующим образом:
перенаправления оцениваются слева направо.

3>&1 Создает новый файловый дескриптор, 3 дубликат (копия) из fd 1 (стандартный вывод).

1>&2 Сделайте stdout (1) дубликатом fd 2 (stderr)

2>&3 Сделайте fd 2, копию (копию) 3, которая ранее была сделана копией stdout.

Так что теперь stderr и stdout переключаются.

| tee foo.file дублирует дескриптор файла 1, который был преобразован в stderr.

Кайл Брандт
источник
О, не тестировал с ksh, работает с bash, хотя ...
Кайл Брандт
Спасибо, тоже работает в кш. Я думаю, что большинство потоковых и потоковых вещей являются стандартом posix.
К. Росс
«Копировать» не совсем правильно - см. Ответ @ Guasqueño.
Кайл Брандт
Это также работает в Windows с tee.exeустановленным :)
Acorn
13

Unix / Linux команда Кайла переключает STDERR с STDOUT; однако объяснение не совсем верно. Операторы перенаправления не выполняют никакого копирования или дублирования, они просто перенаправляют поток в другое направление.

Переписав команду Кайла, временно переместив 3> & 1 в конец, упростит понимание концепции:

find /var/log  1>&2  2>&3  3>&1  

Тем не менее, в таком случае Linux будет отображать ошибку, поскольку & 3 еще не существует, так как он расположен до 3> & 1. 3> что-то - это способ объявить (определить), что мы собираемся использовать третью трубу, так что она должна быть расположена до того, как мы потечем воду в эту трубу, например, так, как это написал Кайл. Попробуйте этот другой способ просто для удовольствия:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

Не иметь возможности делать копии - это позор. Вы не можете делать такие вещи, как «3> & 1 3> & 2» в одной команде, потому что Linux будет использовать только первый найденный и отклонит второй.

Я (пока) не нашел способа отправить как ошибку, так и обычный вывод в файл, а также отправить копию ошибки на стандартный вывод одной командой. Для instace у меня есть задание cron, в котором я хочу, чтобы оба вывода (error и standard) заносились в файл журнала и позволяли также сообщать об ошибке, чтобы отправить сообщение электронной почты на мой blackBerry. Я могу сделать это с помощью двух команд, используя «tee», но ошибка не отображается в правильном порядке среди обычной строки вывода в файле. Это уродливый способ, которым я решил проблему:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Обратите внимание, что я должен использовать log1 дважды, и я должен добавить в обоих случаях, первый из которых использует опцию "-a" для команды "tee", а второй - ">>".

Делая кошку log1 вы получаете следующее:

STD1
STD2
-bash: sdfr: command not found

Обратите внимание, что ошибка не отображается во второй строке, как следует.

Guasqueño
источник
Потрясающая коррекция!
Кайл Брандт
Проверьте zsh и mult_iosпараметр ( включен по умолчанию), чтобы иметь возможность перенаправлять FD несколько раз.
Том Хейл,
2

согласно man-странице для ksh (pdksh), вы можете просто сделать:

Команда 2> & 1> / dev / null | кот-н

то есть dup stderr в stdout, перенаправьте stdout в / dev / null, затем перенаправьте в 'cat -n'

работает на pdksh в моей системе:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
Foo

$ errorecho foo> / dev / null # должен отображаться даже с перенаправленным stdout
Foo

$ errorecho foo 2> & 1> / dev / null | кот-н
     1 фу
$   
саз
источник
Также работает с BusyBox
Udo G
1

Я запустил его так, как ты когда-либо хотел, так как я тоже нуждался в этом и усовершенствовал твою команду. Теперь для меня это работает правильно, используя Bash 3.2 на Debian Squeeze с помощью этого

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

в то время как log1 регистрирует stdout и stderr, а log2 регистрирует только stderr и ничего больше не выводит на экран.

martinseener
источник