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

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 / нуль ,

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

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

$@ 2>&1

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

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

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

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

Will Sheppard
источник
3
Сначала вы должны изменить порядок: 2>&1 > /dev/null означает «2 теперь идет туда, куда идет 1 (т. е. к терминалу по умолчанию), а затем 1 теперь переходит в / dev / null (но 2 по-прежнему идет к терминалу!). use >/dev/null 2>&1 сказать "1 теперь идет в / dev / null, затем 2 идет туда, где 1 идет (то есть также в / dev / null). Это все равно не сработает, поскольку встроенное время не будет перенаправлено, но в целом правильно (например, это будет работать, если вы используете / usr / bin / time). Думайте о "2 & gt; & amp; 1" как о копировании "направления" 1 в 2, а не как 2, переходящее к 1
Olivier Dulac

Ответы:

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?

есть: вывод идет на стандартный вывод или же STDERR ,

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

gniourf_gniourf
источник
2
Вы можете создать другой fd и сделать так, чтобы команды явно обращались к ним (например, в скрипте bash: exec 3>/some/file ; ls >&3 ; )
Olivier Dulac
@OlivierDulac Конечно, или даже проще с coproc встроенный. Но это не так для time встроенный.
gniourf_gniourf
@ gniourf-gniourf: я комментировал из-за твоего предложения "вывод идет в stdout или stderr" ^^
Olivier Dulac
14

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

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

Alok
источник
2
+1. Менее актуален для OP, но более актуален для всех, кто сталкивался с вопросом «Почему вывод некоторых программ linux не идет ни в STDOUT, ни в STDERR?» через гугл. :-)
ruakh
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", затем перенаправляет свой вывод на ноль.

[] S

Márcio
источник
-1

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

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

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

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

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

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

Uwe Plonus
источник
Это не работает с Bash встроенная time, Смотрите мой ответ для некоторых объяснений.
gniourf_gniourf
+1, потому что это полезный ответ на подобный вопрос. Хотя @Olivier объясняет это лучше в комментарии к вопросу выше.
Will Sheppard