20

Почему вывод некоторых программ Linux не идет ни в STDOUT, ни в STDERR?

На самом деле, я хочу знать, как надежно фиксировать весь вывод программы, независимо от того, какой «поток» он использует. У меня проблема в том, что некоторые программы, кажется, не позволяют захватывать их вывод.

Примером является команда time:

time sleep 1 2>&1 > /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

или же

time sleep 1 &> /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

Почему я вижу результат оба раза? Я ожидал, что все это будет передано в /dev/null.

Какой выходной поток использует время, и как я могу передать его в файл?

Один из способов обойти эту проблему - создать скрипт Bash , например, combine.sh содержащий эту команду:

$@ 2>&1

Тогда вывод «времени» может быть записан правильным образом:

combine.sh time sleep 1 &> /dev/null

(ничего не видно - правильно)

Есть ли способ достичь того, что я хочу, без использования отдельного сценария объединения?

4 ответа4

38

Этот вопрос рассматривается в BashFAQ/032. В вашем примере вы бы:

{ time sleep 1; } 2> /dev/null

Причина по которой

time sleep 1 2>/dev/null

не ведет себя так, как вы ожидаете, потому что с этим синтаксисом вы захотите time команду sleep 1 2>/dev/null (да, команда sleep 1 с stderr перенаправлена на /dev/null). Встроенное time работает таким образом, чтобы сделать это действительно возможным.

Встроенный bash может это сделать, потому что ... ну, это встроенный. Такое поведение было бы невозможно с внешним time команды, обычно расположенным в /usr/bin . В самом деле:

$ /usr/bin/time sleep 1 2>/dev/null
$

Теперь ответ на ваш вопрос

Почему вывод некоторых программ linux не идет ни в STDOUT, ни в STDERR?

is: делает, вывод идет в stdout или stderr.

Надеюсь это поможет!

14

Ваш конкретный вопрос о time встроенной команде был дан ответ, но есть некоторые команды , которые не пишут либо на stdout или stderr Классическим примером является crypt команды Unix. crypt без аргументов шифрует стандартный ввод stdin и записывает его в стандартный вывод stdout . Он запрашивает пароль у пользователя с помощью getpass(), который по умолчанию выводит приглашение в /dev/tty . /dev/tty - текущее оконечное устройство. Запись в /dev/tty приводит к записи в текущий терминал (если он есть, см. isatty()).

Причина, по которой crypt не может записать в стандартный stdout заключается в том, что он записывает зашифрованный вывод в стандартный stdout . Кроме того, лучше указывать /dev/tty вместо записи в stderr чтобы, если пользователь перенаправил stdout и stderr , приглашение все равно было видно. (По той же причине, crypt не может прочитать пароль из stdin , так как он используется для чтения данных для шифрования.)

0

time sleep 1 > /dev/null 2>&1 # перенаправляет вывод "sleep" на null. Затем "время" записывает свой собственный вывод, без перенаправления. Это как " time (sleep 1 > /dev/null 2>&1) ".

(time sleep 1) > /dev/null 2>&1 # запускает "time sleep 1", а затем перенаправляет свой вывод в null.

[] S

-1

Проблема в вашем случае заключается в том, что перенаправление работает по-другому. Вы написали

time sleep 1 2>&1 > /dev/null

Это перенаправляет стандартный вывод в /dev/null а затем перенаправляет стандартную ошибку на стандартный вывод.

Чтобы перенаправить весь вывод, вы должны написать

time sleep 1 > /dev/null 2>&1 

Тогда стандартная ошибка будет перенаправлена на стандартный вывод, и после этого все стандартные выходные (содержащие стандартную ошибку) будут перенаправлены на /dev/null .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .