Плутати про stdin, stdout та stderr?


230

Я досить плутаю мету цих трьох файлів. Якщо моє розуміння правильне, stdinце файл, в який програма записує свої запити для виконання завдання в процесі, stdoutце файл, в який ядро ​​записує свій вихід, і процес, який запитує, отримує доступ до інформації, і stderrце файл у які вводяться всі винятки. Відкриваючи ці файли, щоб перевірити, чи дійсно вони трапляються, я виявив, що ніщо так не підказує!

Що я хотів би знати, це яка саме мета цих файлів, абсолютно зведена відповідь з дуже маленьким жаргоном технологій!


36
Спостереження: Це питання було прийнятним ще в 2010 році, але воно буде швидко відхилено сьогодні.
byxor

3
@Brandon Чи можете ви навести причину? Я думаю, це було б цінним для вашого коментаря.
Незалежний

3
@byxor, щоб бути справедливим, я запитаю: чи дописував Оп, щоб люди допомогли йому налагодити свій код? Схоже, Шувік задав питання щодо мети stdin, stdout та stderr. посаду ОП, здається, викликає цікавість, ні? (я насправді про це
дізнаюся

2
@ user123456 ви праві. Я вчився бути розробником програмного забезпечення, і тоді S / O було чудовим місцем для вивчення програм. Спочатку ми мали намір це бути службою вікі-сортування з усіх питань обчислювальної науки. #juniorDevForLife
Shouvik

3
@Shouvik дякую за цей трохи історії. Я також вчуся, як бути розробником програмного забезпечення (щойно прийняли в класний табір в СФ). Я все ще досить новий в S / O і все ще не впевнений, що я можу, а що не можу розмістити. Я вважаю, що поміркованість тут може бути досить суворою. Мені подобається той хеш-тег. #juniorDevForLife. Я б вам вечора замість коментувати тут, оскільки це нічого не додає до дискусії, але я не вірю, що в S / O є система вечора. Гарного дня.
sansae

Відповіді:


251

Стандартне введення - це обробка файлів, яку читає ваш процес, щоб отримати інформацію від вас.

Стандартний вихід - ваш процес записує нормальну інформацію в цю ручку файлу.

Стандартна помилка - ваш процес записує інформацію про помилки в цю ручку файлу.

Це приблизно настільки ж скинуто, як я можу це зробити :-)

Звичайно, це переважно за умовами. Ніщо не заважає вам записати інформацію про помилки на стандартний вихід, якщо хочете. Ви навіть можете повністю закрити три ручки файлів і відкрити власні файли для вводу / виводу.

Коли ваш процес починається, у нього вже повинні бути відкриті ці ручки, і він може просто читати з них та / або писати на них.

За замовчуванням вони, ймовірно, підключені до вашого термінального пристрою (наприклад, /dev/tty), але оболонки дозволять вам встановити з'єднання між цими ручками та конкретними файлами та / або пристроями (або навіть трубопроводами до інших процесів) до початку процесу (деякі з можливі маніпуляції досить розумні).

Приклад:

my_prog <inputfile 2>errorfile | grep XYZ

який:

  • створити процес для my_prog.
  • відкрити inputfileяк стандартний ввід (файл 0).
  • відкрити errorfileяк стандартну помилку (обробка файлу 2).
  • створити інший процес для grep.
  • приєднати стандартний вихід my_progдо стандартного входу grep.

Повторіть свій коментар:

Коли я відкриваю ці файли в папці / dev, то чому я ніколи не бачу результатів роботи процесу?

Це тому, що вони не нормальні файли. Хоча UNIX десь представляє все як файл у файловій системі, це не робить його на найнижчих рівнях. Більшість файлів в /devієрархії - це або символьні, або блокові пристрої, фактично драйвер пристрою. Вони не мають розміру, але вони мають основний та незначний номер пристрою.

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

Те саме стосується /procфайлової системи Linux . Це не справжні файли, а чітко контрольовані шлюзи для інформації ядра.


1
Це для вашої відповіді. Хоча я можу зрозуміти призначення файлів із того, що ви описуєте, я хотів би перейти на рівень більше. коли я відкриваю ці файли в папці / dev, то чому я ніколи не бачу, як працює процес. Скажімо, я виконую зверху на терміналі, чи не слід періодично виводити його результати у файл stdout, отже, коли він оновлюється, я повинен мати змогу побачити екземпляр виводу, який друкується на цей файл. Але це не так. Отже, ці файли не однакові (файли в / dev директорії).
Шувік

7
Тому що це технічно не файли. Вони - вузли пристроїв, які вказують на певний пристрій, для якого потрібно записувати. UNIX може представити вам все як абстракцію файлів, але це не робить це на найглибших рівнях.
paxdiablo

1
Використовуйте можливість перенаправлення оболонки. xyz >xyz.outзапише ваш стандартний вихід у фізичний файл, який може бути прочитаний іншими процесами. xyz | grep somethingпідключить xyzstdout до grepstdin більш безпосередньо. Якщо ви хочете безперешкодний доступ до процесу, який ви не контролюєте таким чином, вам потрібно буде вивчити щось на кшталт /procабо написати код, щоб фільтрувати вихід, якось підключившись до ядра. Можуть бути й інші рішення, але всі вони, мабуть, такі ж небезпечні, як один одного :-)
paxdiablo

20
@Shouvik, зауважте, що /dev/stdinце символьне посилання на /proc/self/fd/0- перший дескриптор файлів, на який відкрита поточна програма. Отже, те, на що вказується, /dev/stdinзміниться від програми до програми, оскільки /proc/self/завжди вказує на "поточну програму". (Яка б програма не робила openдзвінок.) /dev/stdinІ друзів було поміщено туди, щоб зробити встановлені сценарії оболонки безпечнішими, і вони дозволять вам передавати ім'я файлу /dev/stdinпрограмам, які працюють лише з файлами, але ви хочете контролювати їх більш інтерактивно. (Колись це стане для вас корисним трюком. :)
sarnold

1
@ CarlosW.Mercado, файл - це фізичний прояв даних. Наприклад, біти, що зберігаються на жорсткому диску. Ручка файлу - це, як правило, невеликий маркер, який використовується для позначення цього файлу, після його відкриття.
paxdiablo

62

Правильніше було б сказати, що stdin, stdoutі stderrє "потоками вводу / виводу", а не файлами. Як ви помітили, ці об'єкти не живуть у файловій системі. Але філософія Unix, що стосується вводу-виводу, - це "все - файл". На практиці, це дійсно означає , що ви можете використовувати одні і ті ж функції бібліотеки і інтерфейси ( printf, scanf, read, write, selectі т.д.) , не піклуючись про те , чи підключений потік введення / виводу з клавіатури, дисковий файл, сокет, труба, або якась інша абстракція вводу / виводу.

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


Дякуємо за ваші вклади. Чи трапляється вам знати, як я можу перехопити потік вихідних даних процесу та вивести його у власний файл?
Шувік

51

Як доповнення до вищезазначених відповідей, ось підсумок про перенаправлення: Шаблон перенаправлення

EDIT: Ця графіка не зовсім коректна, але я не впевнений, чому ...

Графіка говорить, що 2> & 1 має такий же ефект, як і>

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>

4
Ваш коментар у поєднанні з прийнятою відповіддю має ідеальний сенс і чітко пояснює речі! Дякую!
Микола

1
Картина варта тисячі слів!
tauseef_CuriousGuy

22

Я боюсь, що ваше розуміння повністю відстало. :)

Подумайте про "стандартний", "стандартний вихід" та "стандартну помилку" з точки зору програми , а не з точки зору ядра.

Коли програмі потрібно надрукувати вихід, вона зазвичай друкується на «стандартне виведення». Програма, як правило, друкує вихід на стандартний з printf, який друкує ТОЛЬКО для стандартного виведення.

Коли програмі потрібно друкувати інформацію про помилки (не обов'язково винятки, це конструкція мови програмування, накладена на набагато більш високий рівень), вона зазвичай друкує до "стандартної помилки". Зазвичай це робиться за допомогою fprintf, який приймає потік файлів для використання під час друку. Потоком файлу може бути будь-який файл, відкритий для запису: стандартний вихід, стандартна помилка або будь-який інший файл, відкритий за допомогою fopenабо fdopen.

"standard in" використовується, коли файлу потрібно читати вхід, використовуючи freadабо fgets, або getchar.

Будь-який з цих файлів можна легко переспрямувати з оболонки, наприклад:

cat /etc/passwd > /tmp/out     # redirect cat's standard out to /tmp/foo
cat /nonexistant 2> /tmp/err   # redirect cat's standard error to /tmp/error
cat < /etc/passwd              # redirect cat's standard input to /etc/passwd

Або вся енхілада:

cat < /etc/passwd > /tmp/out 2> /tmp/err

Є два важливих застереження: По-перше, "стандартний режим", "стандартний вихід" та "стандартна помилка" є лише умовою. Вони є дуже сильною умовою, але все це лише домовленість про те, що дуже приємно мати можливість запускати такі програми: grep echo /etc/services | awk '{print $2;}' | sortі мати стандартні виходи кожної програми, підключені до стандартного входу наступної програми в конвеєрі.

По-друге, я дав стандартні функції ISO C для роботи з потоками файлів ( FILE *об'єктами) - на рівні ядра це всі дескриптори файлів ( intпосилання на таблицю файлів) і багато операцій нижчого рівня, таких як readі write, які не виконують виконувати щасливе буферування функцій ISO C. Я подумав зробити це просто і використовувати простіші функції, але я все-таки вважав, що ви повинні знати альтернативи. :)


Так, коли виконується процес, він записує помилки в цей файл stderr або коли програма компілюється з його джерела. Крім того, коли ми говоримо про ці файли з точки зору компілятора, чи відрізняється він від порівняння з програмою скажімо?
Шувік

1
@Shouvik, компілятор - це просто інша програма, яка має власні stdin, stdout та stderr. Коли компілятору потрібно написати попередження або помилки, він запише їх у stderr. Коли передній компілятор виводить проміжний код для асемблера, він може записати проміжний код на stdout, і асемблер може прийняти його вхід на stdin, але все, що буде поза кадром з вашого погляду як користувача.) Після того, як у вас буде складеної програми, ця програма також може записувати помилки до стандартної помилки, але це не має нічого спільного з компілюванням.
sarnold

Дякуємо за цей знак інформації. Я здогадуюсь, що я досить глупо не бачити цього в цій перспективі ...: P
Шовік

1
Отже, ви говорите, що стандарт допомагає нам надрукувати програму
babygame0ver

9

stdin

Читає вхід через консоль (наприклад, введення з клавіатури). Використовується в С із scanf

scanf(<formatstring>,<pointer to storage> ...);

stdout

Виробляє вихід на консоль. Використовується в C з printf

printf(<string>, <values to print> ...);

stderr

Виводить "помилку" на консоль. Використовується в C з fprintf

fprintf(stderr, <string>, <values to print> ...);

Перенаправлення

Джерело для stdin можна перенаправити. Наприклад, замість того, щоб надходити з клавіатурного вводу, він може надходити з файлу ( echo < file.txt) або іншої програми ( ps | grep <userid>).

Місця призначення для stdout, stderr також можна переспрямувати. Наприклад, stdout можна переспрямувати у файл: ls . > ls-output.txtу цьому випадку вихід записується у файл ls-output.txt. Stderr може бути перенаправлений з 2>.


8

Я думаю, що люди, які говорять, stderrслід використовувати лише для повідомлень про помилки, вводять в оману.

Він також повинен використовуватися для інформативних повідомлень, призначених для користувача, який виконує команду, а не для потенційних споживачів даних нижче за течією (тобто, якщо ви запускаєте трубу оболонки, що ланцюгує декілька команд, ви не бажаєте інформаційних повідомлень типу "отримання пункту 30 42424 ", stdoutоскільки вони будуть бентежити споживача, але ви, можливо, все ще хочете, щоб користувач їх бачив.

Дивіться це для історичного обгрунтування:

"Усі програми розміщували діагностику на стандартному виході. Це завжди спричиняло проблеми, коли вихід був перенаправлений у фільтр, але ставав нестерпним, коли вихід був відправлений у нічого не підозрювальному процесі. Тим не менш, не бажаючи порушувати простоту стандартного входу, стандартна модель виводу, люди терпіли такий стан справ через v6. Незабаром після цього Денніс Річі розрізав Гордіїв вузол, ввівши стандартний фільтр помилок. Це було недостатньо. Завдяки діагностиці трубопроводів можна отримати будь-яку з декількох програм, що працюють одночасно. Потрібна діагностика ідентифікувати себе ».


3

Використання ps -aux розкриває поточні процеси, всі вони перелічені в / proc / as / proc / (pid) /, зателефонувавши cat / proc / (pid) / fd / 0, він друкує все, що знаходиться у стандартному виході Я думаю, що цей процес. Тому, можливо,

/ proc / (pid) / fd / 0 - стандартний вихідний файл
/ proc / (pid) / fd / 1 - стандартний вхідний файл
/ proc / (pid) / fd / 2 - стандартний файл помилок

наприкладмоє вікно терміналу

Але це добре працювало для / bin / bash інших процесів, як правило, нічого не було в 0, але у багатьох було помилок, написаних у 2


3

Для отримання достовірної інформації про ці файли, ознайомтеся із довідковими сторінками, запустіть команду на своєму терміналі.

$ man stdout 

Але для простої відповіді кожен файл призначений для:

stdout для витікання

stdin для введення потоку

stderr для друку помилок або повідомлень журналу.

Кожна програма Unix має кожен з цих потоків.


2

stderr не буде виконувати буферизацію кеш-пам’яті IO, тому якщо нашій програмі потрібно буде надрукувати інформацію про критичне повідомлення (деякі помилки, винятки) для консолі або подати файл, де використовувати як stdout для друку загальної інформації журналу, оскільки вона використовує буферизацію кешу IO, є ймовірність, що перед тим, як писати наші повідомлення у файлову програму, може закритися, залишаючи налагодження складним


0

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

https://www.mkssoftware.com/docs/man5/stdio.5.asp

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