Ответ 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
.