Чи належать звіти про хід роботи / реєстрація інформації про stderr чи stdout?


75

Чи є офіційні POSIX, GNU чи інші вказівки щодо того, де слід надрукувати звіти про хід роботи та реєстрацію інформації (такі як "Doing foo; foo done")? Особисто я схильний писати їх до stderr, щоб я міг перенаправляти stdout і отримувати лише фактичний вихід програми. Нещодавно мені сказали, що це не є хорошою практикою, оскільки звіти про прогрес насправді не є помилками, а на stderr слід надрукувати лише повідомлення про помилки.

Обидві позиції мають сенс, і, звичайно, ви можете вибрати ту чи іншу залежно від деталей того, що ви робите, але я хотів би знати, чи є для цього загальноприйнятий стандарт. Мені не вдалося знайти жодних конкретних правил у POSIX, стандартах кодування GNU чи будь-яких інших таких загальновизнаних списках найкращих практик.

У нас є кілька подібних запитань, але вони не вирішують цю точну проблему:

Отже, чи існують офіційні правила, де слід надрукувати звіти про хід роботи та інші інформаційні повідомлення (які не є частиною фактичного результату програми)?


26
Друк прядок тощо - stdoutразом із результатами - безпечний спосіб зробити результати марними. Якщо вам коли-небудь потрібно передавати результати в якусь іншу програму, зазначена програма повинна буде відокремити результати від спінерів. Крім того, якщо ви переймете висновок на файл, ви не зможете побачити спінери. ІМХО.
Satō Katsura

2
@SatoKatsura Так, це теж моя думка, і саме тому я друкую таке на stderr. Офіційний директор компанії, в якій я працюю, однак вважає, що друк на stderr - це ознака того, що щось пішло не так. Я висловив досить сміливе твердження, що POSIX Way® друкується на більш жорсткий, і він викликав мене на це. З огляду на те, що він має 20-річний досвід роботи на мене, я хотів би побачити, чи зможу я знайти якусь "офіційну" інструкцію.
тердон

те, що сказав Сато Кацура, stdoutнасправді є безпечним і правильним способом друкування спінерів та інших інформативних повідомлень, але, як стверджує багато програмістів, «Тиша золота. Нічого не виведіть, якщо все добре ». так насправді, STDERR завжди використовується , щоб зробити це з - за нечіткого визначення , а також стандартний висновок може розірвати трубу sequence.for офіційне керівництво
Se вен

6
@Seven Я думаю, що ти неправильно зрозумів; Сато каже, що використання stdout небезпечно ("безпечний спосіб зробити результати марними").
Стівен Кітт

1
Одним з можливих рішень одного розміру - це використання лише stderrдля повідомлення повідомлень про помилки, за винятком випадків, коли використовується --verboseпрапор, в який також включаються звіти про хід роботи.
Гаурав

Відповіді:


27

Posix визначає стандартні потоки таким чином :

При запуску програми три потоки мають бути заздалегідь визначені і не повинні відкриватися явно: стандартний вхід (для читання звичайного вводу), стандартний вихід (для запису звичайного виводу) та стандартна помилка (для запису діагностичного виводу). При відкритті стандартний потік помилок не буферизований повністю; стандартні вхідні та стандартні вихідні потоки повністю буферизовані лише тоді, якщо потік можна визначити не відноситься до інтерактивного пристрою.

Бібліотека GNU C описує аналогічні стандартні потоки:

Змінна: FILE * stdout
Стандартний вихідний потік, який використовується для нормального виводу з програми.

Змінна: FILE * stderr
Стандартний потік помилок, який використовується для повідомлень про помилки та діагностики, виданих програмою.

Таким чином, стандартні визначення мають невеликі вказівки щодо використання потоку за межами «звичайного / нормального виходу» та «діагностичного / помилкового виведення». На практиці прийнято перенаправляти один або обидва ці потоки на файли та трубопроводи, де індикатори прогресу будуть проблемою. . Деякі системи навіть контролюють stderr вихід і вважають це ознакою проблем. Таким чином, інформація про допоміжний прогрес є проблематичною для будь-якого потоку.

Замість того, щоб безумовно надсилати показники прогресу в будь-який стандартний потік, важливо визнати, що результат прогресу підходить лише для інтерактивних потоків. Зважаючи на це, я рекомендую писати лічильники прогресу лише після перевірки того, чи є потік інтерактивним (наприклад, з isatty()) або коли явно включений параметр командного рядка. Це особливо важливо для лічильників прогресу, які покладаються на поведінку оновлення терміналу, щоб мати сенс, як% -повні смуги.

Для деяких дуже простих повідомлень про прогрес ("Починаючи з X" ... "Зроблено з X") розумніше включати вихід навіть для неінтерактивних потоків. У такому випадку подумайте, як користувачі можуть взаємодіяти з потоками, як-от пошук grepабо перехід на сторінку lessабо моніторинг із ними tail -f. Якщо є сенс бачити повідомлення про прогрес у цих контекстах, їх буде набагато простіше споживати stdout.


Дякую, настанова GNU - це те, про що я хочу. Однак я усвідомлюю, що моє питання було трохи оманливим. Коли я згадав про "звіти про хід", я думав і про такі N% doneречі, як doing fooі подібні речі foo done. Останні завжди слід зберігати, оскільки вони використовуються для налагодження під час перенаправлення до файлу. Тож ваша пропозиція перевірити, чи інтерактивний потік не застосовується (хоча загалом це дуже гарна ідея).
тердон

А, дякую за уточнення, це трохи відрізняється від таких речей, як "% завершений" та хеш-позначки прогресу, які ви бачите в програмному забезпеченні, як curlі yum. У цьому випадку, я думаю про те, чи буде і яким чином користувач хоче взаємодіяти з виходом через grepабо lessабо аналогічні інструменти.
Бредд Шоні

Оновлена ​​відповідь, щоб включити пояснення вище.
Бредд Шоні

71

POSIX визначає стандартну помилку як

для написання діагностичного виводу

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


8
FWIW в Python stdoutза замовчуванням буферизується за рядками, тоді як stderrє нерозподіленим, тому stderrє природним вибором для написання тексту прогресу / барів / спінерів, які не містять нової лінії . (Якщо ви пишете такий текст, stdoutвам потрібно захаращувати свої виклики прогресу, stdout.flush()щоб зробити його видимим).
PM 2Ring

12
@ PM2Ring, що не характерно для Python, POSIX визначає потоки таким чином.
Стівен Кітт

4
@ PM2Ring: При записи stdout, ви повинні очистити навіть якщо текст справді містить символ нового рядка , якщо ви хочете , щоб ваші звіти про хід робіт на самому ділі показати в режимі реального часу , коли перенаправлені.

@Hurkyl Ах, хороший момент. Я не розглядав перенаправлення.
20:00 16

1
@Wtower, так? Ні. Відповідальний заковтує строгіший текст, якщо статус виходу становить 0. Це твердження просто помилкове.
Чарльз Даффі

10

POSIX трохи конкретніше щодо "діагностичної інформації" у програмі Shell and Utilities , 1.4: Опис утиліти за замовчуванням (наголос моє):

STDERR

Розділ STDERR описує стандартний вихід помилки утиліти. Описані лише ті повідомлення, які спеціально надсилаються утилітою. Використання терміналу для стандартної помилки може зупинити будь-яку зі стандартних утиліт, які записують стандартний вихід помилки, коли використовується у фоновому режимі. З цієї причини програми не повинні використовувати інтерактивні функції у сценаріях, розміщених у фоновому режимі.

Формат діагностичних повідомлень для більшості утиліт не визначений, але на мову та культурні конвенції діагностичних та інформаційних повідомлень, формат яких не визначений цим обсягом POSIX.1-2008, має впливати налаштування LC_MESSAGES та [XSI] [Опція Старт ] НЛСПАТ. [Варіант Кінець]

Зазначений вихід стандартної помилки стандартних утиліт не повинен залежати від існування або значення змінних середовища, визначених у цьому обсязі POSIX.1-2008, за винятком випадків, передбачених цим обсягом POSIX.1-2008.

Поведінка за замовчуванням : Коли цей розділ вказаний як "Стандартна помилка повинна використовуватися лише для діагностичних повідомлень". Це означає, що, якщо не вказано інше, діагностичні повідомлення надсилаються до стандартної помилки лише тоді, коли стан виходу вказує, що помилка сталося, і утиліта використовується як описано в цьому томі POSIX.1-2008.

Якщо цей розділ вказаний як "Не використовується", це означає, що стандартна помилка не повинна використовуватися, коли утиліта використовується, як описано в цьому томі POSIX.1-2008.

IANASL, але я тлумачу, що це означає, що stderr матиме вихід, лише якщо утиліта поверне код виходу з помилки. Оскільки це не повинен бути звичайним ходом подій для успішного виконання, жодна інформація про хід не повинна друкуватися утилітою POSIX, якщо не трапляється помилка (якщо, звичайно, не вказано інше тощо).


Я розумію це як опис значення розділу "STDERR", наведеного в специфікаціях кожної утиліти POSIX, а не як загальне визначення для використання стандартних помилок. Я не думаю, що тердон пише тут стандартну утиліту POSIX ;-).
Стівен Кітт

1
@StephenKitt так само і я. Але він дискутує зі своїм CTO, який каже, що більш жорсткий вихід є ознакою того, що щось не так, і стандарт підтримує його вимогу як поведінку за замовчуванням.
муру

1
Він підтримує претензію як поведінку за замовчуванням для утиліт POSIX , і навіть тоді лише в конкретних випадках (утиліти, які використовують згадану фразу). Ця частина POSIX не є нормативною (AIUI), це шаблон: він говорить про те, як читати специфікації утиліти, не визначає поведінку утиліт. Зокрема, він визначає значення фраз "Стандартна помилка повинна використовуватися лише для діагностичних повідомлень". та "Не використовується". у розділах "STDERR" специфікацій утиліти. Кожна утиліта визначає свою поведінку, і вона може використовувати ці фрази як скорочення.
Стівен Кітт

@StephenKitt, яка не змінює мою точку зору. Утиліти POSIX а) не виводять на stderr, б) використовують його лише для діагностичних повідомлень, якщо щось піде не так; Я сказав, що вони використовують його лише для діагностичних повідомлень, якщо щось піде не так (a, b), якщо інше не вказано (c, d). Тепер я стверджую, що це типовий стандарт, який, безумовно, є, тому що це шаблон.
муру

2
Ну, я б сказав, що "якщо не вказано інше", є досить важливим застереженням: утиліта POSIX цілком може вказати, що вона виводить інформацію про хід своєї стандартної помилки, і вона буде відповідати стандартам. Ви маєте рацію, цікаво, що "поведінка за замовчуванням" (яка все-таки вимагає конкретної згадки у відповідному розділі) полягає у використанні лише стандартної помилки, якщо код виходу також вказує на помилку; але це не обмежує.
Стівен Кітт

7

За принципом виключення воно може перейти лише до більш жорсткого. Так, я знаю, що ви запитали про офіційну специфікацію, яку я не можу представити за межами посилання на специфікацію POSIX, наданої Стівеном Кіттом, в якому зазначено, що stderr призначений для діагностичних цілей.

Більш важливим моментом є те, що stdin і stdout мають функцію, яка забороняє друкувати звіти про хід виконання stdout - вони, звичайно, утворюють послідовність труб, що в командах оболонки Unix є не просто побічним ефектом, а самою сутністю потужного підхідного конвеєра. .

Тому. Ніщо, крім реального «корисного навантаження» вашої програми, не належить до stdout. Якщо у вашої програми немає результатів, то нічого не повинно йти на stdout. Це залишає складніше для всього іншого , включаючи звіти про хід діяльності.

Зрозуміло, це залишає дірку - можливо, було б добре мати "stdfluff" або щось подібне, яке не має жодних результатів, ані помилок, але звітів про прогрес, налагодження та щось подібне. Насправді, ніщо не заважає вам цього робити, тобто ви можете надрукувати свій прогрес у дескрипторі файлів 3. Приклад:

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'

Це не дає результату. (*)

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'  3>&1
hello

Це друкує на fd-3, який перенаправляється на stdout.

(*) Перший приклад не дає результатів, але все ще трохи надуманий; openзазнає невдачі і $!буде містити no such file or directory; просто візьміть це як приклад, це, звичайно, не настільки, щоб серйозно використовувати це. У дійсній програмі, якщо ви хочете пройти цей маршрут, ви можете перевірити, чи /dev/fd/3є він придатним для використання, і сприйняти це як підказку щодо активації ваших звітів про хід; вам доведеться це зробити досить рано, щоб ви не заплуталися у власних opensх для реальних файлів і подібних ...


Що таке fd-3? Третя дискета?
Пітер Мортенсен

дескриптор файлу 3, @PeterMortensen
AnoE

-1

Повідомлення про використання повинно переходити до stdout, якщо користувач викликав його, --helpі stderr, якщо він допустив помилку. Роздрукувати його на stderr беззастережно - це неприємно, оскільки це ускладнює перегляд його за допомогою пейджера / grep / тощо.

Також, я можу запропонувати третій спосіб: відкрити / dev / tty для звітів про хід / спінери / тощо.


6
Вибачте, але це не відповідає на питання. Я спеціально просив офіційних вказівок, а не думки. У будь-якому випадку, навіть якби я попросив думку, ви відповідаєте на інше запитання. Я взагалі не говорю про --helpабо допомагаю повідомленням. Перечитайте запитання.
тердон

Ви згадали про "повідомлення про використання", я вважав, що це частина вашого запитання, а не лише назва іншого питання, яке ви пов’язали. Я не розумію, чому ви вважаєте, що для цього існують "офіційні вказівки". Хто мав би повноваження їх робити?
Випадково832

3
Я не знаю, що вони роблять, тому я прошу. А що стосується офіційного, то стандарт POSIX має технічні характеристики для різних детальних відомостей про поведінку програми. В тому числі, як зазначив Стівен у своїй відповіді, невиразну пропозицію щодо того, що має йти до більш жорсткого. Стандарт кодування GNU також може мати щось подібне. В основному, будь-яка група, яка активно працює і виробляє код для екосистеми * nix, може мати стандарт, який мене зацікавив би
terdon

@terdon, чи добре ви будете з прикладами того, що роблять існуючі програми? curl, wget та pv використовують stderr, при цьому wget та pv умовляють, що це tty та curl, що умовляє stdout, не будучи tty.
Випадково832

4
Крім того, здається, що ваш CTO вважає, що програма, що викликає, повинна реагувати на наявність даних на stderr, оскільки це означає, що сталася помилка, а не дивитися на стан виходу. Це, безумовно, погана практика (а також важче написати, ніж перевірка статусу виходу) і може бути кращим кутом, щоб переконати його.
Випадково832
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.