Подтвердить что ты не робот

Как перенаправить STDERR на STDOUT, но игнорировать исходный STDOUT?

У меня есть программа, чей вывод STDERR я хочу проверить и запустить grep и т.д.

Поэтому я мог бы перенаправить его на STDOUT и использовать grep, но проблема в том, что я не хочу исходный STDOUT контент.

Итак, этот не будет делать

cmd 2>&1 | grep pattern

потому что он будет смешивать оригинальные STDOUT и STDERR.

И этот не работает, поскольку grep не читает вывод STDERR:

cmd 1>/dev/null | grep pattern

Но и этот не будет работать:

cmd 1>/dev/null 2>&1 | grep pattern

потому что вывод будет полностью пустым, поскольку все будет записано в /dev/null.

Но должен ли быть простой способ сделать это?

4b9b3361

Ответ 1

Что не работает:

Причина последней приведенной вами команды:

cmd 1>/dev/null 2>&1 | grep pattern

не работает, проистекает из путаницы в том порядке, в котором работает перенаправление. Вы ожидали, что последнее цитированное перенаправление будет применено к тем, которые были перед ним на каждом выходе, так что вывод исходного дескриптора исходного файла вывода (1) будет идти в /dev/null, а вывод в стандартный дескриптор файла ошибки (2) будет перейти к исходному стандарту вывода.

Однако это не так, как работает перенаправление оболочки. Каждое перенаправление приводит к тому, что дескрипторы файлов "перенаправляются", закрывая "источник" и дублируя "место назначения" в нем (см. Страницы man dup(2) и close(2)) по порядку. Это означает, что в вашей команде стандартный вывод сначала заменяется на /dev/null, а затем стандартная ошибка заменяется на стандартный вывод, который уже /dev/null.

Что работает:

Поэтому, чтобы получить желаемый эффект, вам просто нужно отменить перенаправления. Затем у вас будет стандартная ошибка, идущая на стандартный вывод, а исходный стандартный вывод - /dev/null:

cmd 2>&1 >/dev/null | grep pattern

(обратите внимание, что 1 до > не требуется - для стандартного вывода перенаправления вывода используется значение по умолчанию)


Приложение: Чарли упомянул о перенаправлении на &-, чтобы закрыть дескриптор файла. Если использовать интерактивную оболочку, поддерживающую это расширение (bashи некоторые другие реализации, но не все, и это не стандарт), вы также можете сделайте это так:

cmd 2>&1 >&- | grep pattern

Это может быть лучше - это может сэкономить некоторое время, потому что когда команда пытается записать на стандартный вывод, вызов write может выйти из строя немедленно, не дожидаясь перехода контекста в ядро ​​и обработки драйвера /dev/null ( в зависимости от реализации системного вызова - некоторые могут поймать это в функции libc, а некоторые могут также иметь специальную обработку для /dev/null). Если есть много выходных данных, которые могут быть полезны, и это быстрее ввести.

Это будет работать в основном потому, что большинство программ не заботятся о том, что они не могут писать на стандартный вывод (кто действительно проверяет возвращаемое значение printf?) и не будет возражать против закрытия стандартного вывода. Но некоторые программы могут сгенерировать код отказа, если write не работает - обычно блокируют процессоры, программы используют некоторую осторожную библиотеку для ввода-вывода или протоколирования вывода stdandard. Поэтому, если он не работает, помните, что это вероятная причина и попробуйте /dev/null.

Ответ 2

Сначала закройте STDOUT:

1>&-, >&-

Смотрите здесь.

Ответ 3

Я бы попробовал что-то простое:

cmd 2> tmp_file && cat tmp_file | grep pattern && rm -f tmp_file