Как подключить stderr, а не stdout?
У меня есть программа, которая записывает информацию в stdout
и stderr
, и мне нужно grep
через то, что поступает в stderr, не обращая внимания на stdout.
Я могу, конечно, сделать это за 2 шага:
command > /dev/null 2> temp.file
grep 'something' temp.file
но я предпочел бы иметь возможность делать это без временных файлов. Есть ли какие-нибудь умные трюки?
Ответы
Ответ 1
Сначала перенаправить stderr в stdout - трубу; затем перенаправить stdout на /dev/null
(без изменения, где происходит stderr):
command 2>&1 >/dev/null | grep 'something'
Подробные сведения о перенаправлении ввода-вывода во всем его разнообразии см. в главе Redirections справочного руководства Bash.
Обратите внимание, что последовательность переназначений ввода/вывода интерпретируется слева направо, но каналы настроены до интерпретации ввода-вывода. Файловые дескрипторы, такие как 1 и 2, являются ссылками на описания открытых файлов. Операция 2>&1
делает файловый дескриптор 2 aka stderr ссылкой на то же самое описание открытого файла, что и дескриптор файла 1 aka stdout, в настоящее время ссылается на (см. dup2()
и open()
). Операция >/dev/null
затем изменяет дескриптор 1 файла, так что он ссылается на описание открытого файла для /dev/null
, но это не меняет того факта, что дескриптор файла 2 относится к описанию открытого файла, в котором дескриптор 1 файла первоначально указывал на - а именно, трубы.
Ответ 2
Или обменять вывод из stderr и stdout на использование: -
command 3>&1 1>&2 2>&3
Это создает новый файловый дескриптор (3) и назначает его в то же место, что и 1 (stdout), затем назначает fd 1 (stdout) в то же место, что и fd 2 (stderr), и, наконец, назначает fd 2 (stderr) тому же место как fd 3 (стандартный вывод). Stderr теперь доступен как stdout, а старый stdout сохранен в stderr. Это может быть излишним, но, надеюсь, даст больше подробностей о дескрипторах файлов bash (для каждого процесса доступно 9).
Ответ 3
В Bash вы также можете перенаправить на подоболочку с помощью замены процесса:
command > >(stdlog pipe) 2> >(stderr pipe)
В данном случае:
command 2> >(grep 'something') >/dev/null
Ответ 4
Объединяя лучшие из этих ответов, если вы делаете:
command 2> >(grep -v something 1>&2)
... тогда все stdout сохраняются как stdout, а все stderr сохраняются как stderr, но вы не увидите никаких строк в stderr, содержащих строку "что-то".
Это имеет уникальное преимущество, заключающееся в том, что они не меняют и не отбрасывают stdout и stderr, не соединяют их вместе и не используют какие-либо временные файлы.
Ответ 5
Намного легче визуализировать вещи, если вы думаете о том, что действительно происходит с "перенаправлением" и "трубами". Перенаправления и каналы в bash делают одно: измените, где дескрипторы файла процесса 0, 1 и 2 указывают на (см./Proc/[pid]/fd/*).
Когда pipe или "|" оператор присутствует в командной строке, первое, что произойдет, - это то, что bash создает fifo и указывает левую командную команду FD 1 на этот fifo и указывает правую боковую команду FD 0 на ту же самую fifo.
Далее, операторы перенаправления для каждой стороны оцениваются слева направо, а текущие настройки используются всякий раз, когда происходит дублирование дескриптора. Это важно, поскольку, поскольку сначала был настроен канал, FD1 (левая сторона) и FD0 (правая сторона) уже изменены с того, что они могли бы быть, и любое дублирование этих будет отражать этот факт.
Поэтому, когда вы вводите что-то вроде следующего:
command 2>&1 >/dev/null | grep 'something'
Вот что происходит, в порядке:
- создается труба (fifo). "Команда FD1" указана на этот канал. "grep FD0" также указывается на этот трубопровод
- "команда FD2" указывает на то, где "команда FD1" в настоящее время указывает (труба)
- "команда FD1" указана на /dev/null
Итак, весь вывод, который "команда" записывает в его FD 2 (stderr), пробивается к трубе и читается "grep" с другой стороны. Весь вывод, который "команда" записывает в его FD 1 (stdout), пробивается к /dev/null.
Если вместо этого вы запускаете следующее:
command >/dev/null 2>&1 | grep 'something'
Вот что происходит:
- создается труба и указывается "команда FD 1" и "grep FD 0"
- "команда FD 1" указана на /dev/null
- "команда FD 2" указывается на то, где в настоящее время указывает FD 1 (/dev/null)
Итак, все stdout и stderr из "command" идут в /dev/null. Ничего не происходит в трубе, и, таким образом, "grep" будет закрываться, не отображая ничего на экране.
Также обратите внимание, что перенаправления (дескрипторы файлов) могут быть доступны только для чтения (<), только для записи ( > ) или read-write (< > ).
Последняя заметка. Независимо от того, записывает ли программа что-то в FD1 или FD2, полностью зависит от программиста. Хорошая практика программирования диктует, что сообщения об ошибках должны перейти на FD 2 и нормальный выход в FD 1, но вы часто найдете неаккуратное программирование, которое смешивает два или иначе игнорирует соглашение.
Ответ 6
Используете ли вы bash? Если да:
command >/dev/null |& grep "something"
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
Ответ 7
Для тех, кто хочет перенаправлять stdout и stderr навсегда, grep на stderr, но сохраняйте stdout для записи сообщений в tty:
# save tty-stdout to fd 3
exec 3>&1
# switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
# goes to the std.out
echo "my first message" >&1
# goes to the std.err
echo "a error message" >&2
# goes nowhere
echo "this nasty_msg won't appear anywhere" >&2
# goes to the tty
echo "a message on the terminal" >&3
Ответ 8
Это перенаправит команду command1 stderr на команду command2 stdin, оставив команду command1 stdout как есть.
exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-
Взято из ЛДП
Ответ 9
Я только что предложил решение для отправки stdout
одной команде и stderr
другой, используя именованные каналы.
Вот оно.
mkfifo stdout-target
mkfifo stderr-target
cat < stdout-target | command-for-stdout &
cat < stderr-target | command-for-stderr &
main-command 1>stdout-target 2>stderr-target
Вероятно, это хорошая идея удалить именованные каналы позже.
Ответ 10
Я склонен делать такие вещи, как
тест композитора & >>/tmp/bob && vim/tmp/bob && rm/tmp/bob
Ответ 11
Я пытаюсь следовать, найти это работать, а также,
command > /dev/null 2>&1 | grep 'something'