Чому вихід деяких програм Linux не переходить ні на STDOUT, ні на STDERR?


21

Чому вихід деяких програм 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

Тоді висновок 'time' може бути записаний правильним чином:

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

(вихід не видно - правильний)

Чи є спосіб досягти того, що я хочу, не використовуючи окремий комбінований сценарій?


3
спочатку ви повинні змінити порядок: 2>&1 > /dev/nullкошти «2 в даний час йде туди , де 1 йде (тобто термінал за замовчуванням), а потім 1 тепер йде / DEV / нуль (але 2 все ще йде в термінал!) використовувати. >/dev/null 2>&1сказати "1 переходить зараз до / dev / null, потім 2 іде туди, куди йде 1 (тобто також до / dev / null). Тут все одно не буде працювати, оскільки вбудований "час" не буде переспрямовано, але, як правило, правильніше (наприклад, воно буде працювати, якщо ви використовуєте / usr / bin / time). Подумайте про "2> і 1", як про копіювання 1-го "напрямку" на 2, а не про те, що 2 буде 1
Олів'є Дулак

Відповіді:


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?

є: так, вихід йде в stdout або stderr .

Сподіваюся, це допомагає!


2
Ви можете створити інші ФД і є команди явно йдуть до тих (наприклад: в БАШЕЄВ скрипта: exec 3>/some/file ; ls >&3 ;)
Олів'є Дюлак

@OlivierDulac Звичайно, або ще простіше з coprocвбудованим. Але це не так для timeвбудованого.
gniourf_gniourf

@ gniourf-gniourf: Я коментував ваше твоє речення "вихід іде на stdout або stderr" ^^
Олів'є Дулак

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, оскільки він використовується для зчитування даних для шифрування.)


2
+1. Менш релевантний для ОП, але більш актуальний для всіх, хто стикається "Чому вихід деяких програм Linux не переходить ні на STDOUT, ні на STDERR?" через Google. :-)
ruakh

0

time sleep 1 > /dev/null 2>&1Вихід # переспрямування "сну" робить null. Потім "час" записує власний висновок, без перенаправлення. Це як " time (sleep 1 > /dev/null 2>&1)".

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

[] с


-1

Проблема у вашому випадку полягає в тому, що перенаправлення працює іншим способом. Ти написав

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

Це перенаправляє стандартний висновок на, /dev/nullа потім перенаправляє стандартну помилку на стандартний вихід.

Щоб перенаправити весь результат, який потрібно записати

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

Тоді стандартна помилка буде переспрямована на стандартний вихід і після цього весь стандартний вихід (містить стандартну помилку) буде переспрямований на /dev/null.


Це не працює з bash вбудованим time . Дивіться мою відповідь для деяких пояснень.
gniourf_gniourf

+1, оскільки це корисна відповідь на подібне запитання. Хоча @Olivier пояснює це краще в коментарі до питання вище.
Вілл Шеппард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.