Як сказати, чи є вихід сценарію команди або оболонки stdout або stderr


32

Скажімо, я запускаю сценарій команди або оболонки, і це дає мені вихід. Не знаючи внутрішніх даних цієї команди або скрипта оболонки, як можна визначити, чи був вихід з stderrабо stdout?

Наприклад,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

проти

ls -ld /test
ls: /test: No such file or directory

Як я можу встановити, що перша команда надрукована, stdoutа друга - stderr(зробив це?)?


1
Яку проблему ви намагаєтеся тут вирішити?
Кенстер

3
Боявся, що хтось це запитає; ніхто насправді, здебільшого цікавий і сподівається покращити моє розуміння перенаправлення.
КМ.

7
Ви можете помістити stderredу вашій оболонці навколишнього середовища , LD_PRELOADщоб отримати stdoutі stderrв різних кольорах. Ось відповідне питання в цьому напрямку.
Анко

Відповіді:


18

Немає можливості сказати, коли вихід вже надрукований. У цьому випадку обидва stdoutі stderrпідключені до терміналу, тому інформація про те, в який потік був записаний, вже втрачалася з моменту появи тексту на вашому терміналі; їх об'єднала програма, перш ніж потрапити в термінал.

Що ви можете зробити у випадку, як описано вище, було б запустити команду stdoutта stderrпереспрямувати її в різні місця та подивитися, що відбувається. Або запустіть його двічі, один раз з stdoutпереспрямованим на /dev/nullі один раз з stderrперенаправленим на /dev/null, і подивіться, який із цих випадків призводить до появи тексту.

Ви можете перенаправити stdoutдо /dev/nullпо лавіруючи >/dev/nullна кінці командного рядка, і ви можете перенаправити stderrдо /dev/nullшляху додавання 2>/dev/null.


9

Ви можете перенаправляти stdout за допомогою > fileта перенаправляти stderr за допомогою 2> file. Багато сучасних оболонок підтримують перенаправлення на команди, тому ви можете sedвиділити, який вихід надходить з якого потоку:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

Дуже хороша! Було б чудово, якби можна було виділити лінії кольорами, а не префіксом.
dotancohen

3
@dotancohen: Можна! Напр.,(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
PM 2Ring

Зауважте, що якщо є змішаний вихід із stdout та stderr, спочатку буде видано stdout, а потім stderr.
nyuszika7h

5

annotate-outputСкрипт з Debian - х devscriptsдозволяє робити це вибірково:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

Другий стовпець вказує stdout і stderr з Oі Eвідповідно.

Є деякі застереження, головне з яких було зазначено в інших відповідях: ви не можете цього зробити після факту. Ні оболонка, ні термінал не знають, як довільна програма використовує свої дескриптори файлів, хоча оболонка відповідає за їх початкове налаштування.

Цей метод використовує фіфос, запис у фіфо може поводитись інакше, ніж писати в tty, а запис на два різні файли однозначно відрізняється (можливі проблеми з тимчасовим перемежуванням). Крім того, він не підходить для інтерактивного використання, наприклад, annotate-output bashце не чудовий план, але він корисний для багатьох інших цілей. Є багато, багато прикладів скриптів і функцій оболонки у відповідях на відповідні запитання про колоризацію stdin / stdout / stderr, найбільш надійним є stderrd, який використовує модифікацію виконання (більшості) програм для зміни даних, записаних на stderr.

На це питання, на яке посилається Анко, є відповіді на відповідну тему: колоризація виводу stdout / stderr: Чи можу я налаштувати свою оболонку для друку STDERR та STDOUT різними кольорами?


1
Зауважте, що це bashсценарій з використанням while readциклів і виконання однієї dateкоманди для кожного рядка stdout або stderr, тому він буде набагато менш ефективним, ніж cmd > >(ts '%T O:') 2> >(ts '%T E:')еквівалент.
Стефан Шазелас

1

Окрім інших відповідей, цікаво вказати /proc/$PID/fd(хоча це не відповідає на питання):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

Як бачите, тут ви можете побачити дескриптори файлів, відкриті для процесу. 0є STDIN, 1є STDOUTі 2є STDERR. Якщо у вас не було перенаправлено STDOUT або STDERR, ви побачите /dev/pts/33(принаймні в цьому прикладі), оскільки вони вказували б на термінал.

Примітки : /proc/$PIDіснує лише для запущених процесів. У цьому випадку я використовував catбез аргументів, тому це не закінчується, поки я не закрию STDIN. Я також виконав його у фоновому режимі, тому я отримав PID негайно заради цього прикладу.


0

Не зовсім зрозуміло, про що ви питаєте, але це може допомогти

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

Джерело

Якщо код виходу 0, це просто означає, що команда виконується правильно (stdout), тут ви можете знайти значення, якщо код виходу відрізняється від 0 (stderr)


Дуже цікаво! Я б ніколи не пов'язував статуси виходу з перенаправленням. Має на увазі нуль stdoutі ненульовий stderr?
КМ.

7
@KM., Ні. Я б сказав, що це сильно корелює, але ніщо не зупиняє програму від написання stderrта повернення хорошого коду помилки або запису до stdoutта повернення поганого коду помилки. Справді, спробуйте find /root- якщо припустити, що ви не запущено як root, вам слід вивести два рядки - "/ root" надруковується stdout, а "find: / root: Permissions disabled" надруковується stderr. І знайде повернення поганий код повернення.
godlygeek

Проблема ОП зрозуміла, що як сказати, що таке stdout чи stderr.
it_is_a_literature

0

Зазвичай STDERR матиме ім'я програми, подане до повідомлення з двокрапкою.

Приклад:

rpm -zq some_utils 
rpm: -zq: unknown option

Vs

rpm -ql some_utils 
package some_utils is not installed

-1

Щоб захопити та перевірити вихід помилок:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.