Смущены stdin, stdout и stderr?


230

Я довольно запутался с целью этих трех файлов. Если я правильно понимаю, stdinэто файл, в который программа записывает свои запросы на выполнение задачи в процессе, stdoutэто файл, в который ядро ​​записывает свои выходные данные, и процесс, запрашивающий его, получает доступ к информации и stderrявляется ли этот файл в которые все исключения введены. Открыв эти файлы, чтобы проверить, действительно ли они происходят, я не нашел ничего, что могло бы предложить это!

То, что я хотел бы знать, какова цель этих файлов, абсолютно тупой ответ с очень небольшим техническим жаргоном!


36
Замечание: этот вопрос был приемлем в далеком 2010 году, но в настоящее время очень быстро будет отвергнут.
17

3
@ Брэндон Можете ли вы указать причину? Я думаю, что это было бы полезно для вашего комментария.
Независимо

3
@byxor, чтобы быть справедливым, я спрошу: пост опа просил людей помочь ему отладить его код? кажется, Шоувик задал вопрос о назначении stdin, stdout и stderr. пост опа, кажется, из любопытства, нет? (Я сам
узнаю

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

3
@Shouvik спасибо за эту историю. Я учусь, как быть разработчиком программного обеспечения (только что меня приняли в крутой лагерь в SF). Я все еще довольно новичок в S / O и все еще не уверен в том, что я могу и не могу отправлять. Я считаю, что модерация здесь может быть довольно строгой. Мне нравится этот хэш-тег. #juniorDevForLife. Я бы написал вам вместо того, чтобы комментировать, потому что это ничего не добавляет к обсуждению, но я не верю, что S / O имеет систему pm Хорошего дня.
Sansae

Ответы:


251

Стандартный ввод - это дескриптор файла, который ваш процесс читает, чтобы получить информацию от вас.

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

Стандартная ошибка - ваш процесс записывает информацию об ошибке в этот дескриптор файла.

Это настолько глупо, насколько я могу это сделать :-)

Конечно, это в основном по соглашению. Ничто не мешает вам записать информацию об ошибках в стандартный вывод, если хотите. Вы даже можете полностью закрыть три файловых дескриптора и открыть свои собственные файлы для ввода / вывода.

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

По умолчанию они, вероятно, подключены к вашему оконечному устройству (например, /dev/tty), но оболочки позволят вам установить соединения между этими дескрипторами и конкретными файлами и / или устройствами (или даже конвейерами к другим процессам) до запуска вашего процесса (некоторые из возможные манипуляции довольно умны).

Примером является:

my_prog <inputfile 2>errorfile | grep XYZ

который будет:

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

Re ваш комментарий:

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

Это потому что они не нормальные файлы. В то время как UNIX представляет все как файл в файловой системе где-то, это не делает это на самых низких уровнях. Большинство файлов в /devиерархии являются символьными или блочными устройствами, фактически драйвером устройства. У них нет размера, но у них есть старший и младший номер устройства.

Когда вы открываете их, вы подключаетесь к драйверу устройства, а не к физическому файлу, и драйвер устройства достаточно умен, чтобы знать, что отдельные процессы должны обрабатываться отдельно.

То же самое верно для /procфайловой системы Linux . Это не настоящие файлы, это просто строго контролируемые шлюзы с информацией о ядре.


1
Вот за ваш ответ. Хотя я могу понять назначение файлов из того, что вы описываете, я бы хотел больше перенести уровень. когда я открываю эти файлы в папке / dev, почему я никогда не вижу вывод запущенного процесса. Скажем, я выполняю top на терминале, разве он не должен периодически выводить свои результаты в файл stdout, поэтому, когда он обновляется, я должен иметь возможность увидеть экземпляр вывода, выводимого в этот файл. Но это не так .. Значит, эти файлы не совпадают (те, что в каталоге / dev).
Шоувик

7
Потому что это технически не файлы. Это узлы устройства, указывающие конкретное устройство для записи. UNIX может представить вам все как файловую абстракцию, но это не делает это на самых глубоких уровнях.
paxdiablo

1
Используйте возможность перенаправления оболочки. xyz >xyz.outзапишет ваш стандартный вывод в физический файл, который может быть прочитан другими процессами. xyz | grep somethingподключит стандартный xyzвывод к стандартному grepвводу напрямую. Если вам нужен беспрепятственный доступ к процессу, который вы не контролируете таким образом, вам нужно изучить что-то вроде /procили написать код, чтобы отфильтровать вывод, каким-то образом подключившись к ядру. Могут быть и другие решения, но все они, вероятно, так же опасны, как и другие :-)
paxdiablo

20
@Shouvik, обратите внимание, что /dev/stdinэто символическая ссылка /proc/self/fd/0на первый дескриптор файла, который открыта в настоящий момент запущенной программой. Таким образом, то, на что указывает, /dev/stdinбудет меняться от программы к программе, потому что /proc/self/всегда указывает на «запущенную программу». (Какая бы программа ни выполняла openвызов.) /dev/stdinИ друзей отправили туда, чтобы сделать сценарии оболочки setuid более безопасными, и позволить передавать имя файла /dev/stdinпрограммам, которые работают только с файлами, но вы хотите управлять более интерактивно. (Когда-нибудь это будет полезная уловка для вас. :)
sarnold

1
@ CarlosW.Mercado, файл является физическим проявлением данных. Например, биты хранятся на жестком диске. Файл ручка (обычно) небольшой знак , используемый для обозначения этого файла, как только вы открыли его.
paxdiablo

62

Было бы правильнее сказать , что stdin, stdoutи stderrявляются «I / O потоков» , а не файлы. Как вы заметили, эти сущности не живут в файловой системе. Но философия Unix, что касается ввода / вывода, заключается в том, что «все это файл». На практике, это действительно означает , что вы можете использовать одни и те же функции библиотеки и интерфейсы ( printf, scanf, read, write, selectи т.д.) , не заботясь о том , подключен ли поток ввода / вывода с клавиатуры, дисковый файл, сокет, труба, или какая-то другая абстракция ввода / вывода.

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


Спасибо за ваш вклад. Вы случайно не знаете, как я мог бы перехватить поток выходных данных процесса и вывести его в собственный файл?
Шоувик

51

В качестве дополнения к ответам, приведенным выше, ниже приводится сводная информация о перенаправлениях: Таблица перенаправлений

РЕДАКТИРОВАТЬ: эта графика не совсем правильно, но я не уверен, почему ...

На рисунке написано, что 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.

«Стандартный вход» используется, когда файл должен прочитать ввод, используя 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, но все это будет за кадром с вашей точки зрения как пользователя.) Как только вы получите скомпилированная программа, эта программа также может записывать ошибки в свою стандартную ошибку, но она не имеет ничего общего с компиляцией.
Сарнольд

Спасибо за этот знак информации. Я думаю, это довольно глупо с моей стороны не видеть это в такой перспективе в любом случае ...: P
Shouvik

1
Итак, вы говорите, что стандарт помогает нам напечатать программу
babygame0ver

9

STDIN

Читает ввод через консоль (например, ввод с клавиатуры). Используется в C с scanf

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

стандартный вывод

Производит вывод на консоль. Используется в 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потому что они могут запутать потребителя, но вы все равно хотите, чтобы пользователь их увидел.

Смотрите это для исторического обоснования:

«Все программы помещали диагностику на стандартный вывод. Это всегда вызывало проблемы, когда вывод перенаправлялся в файл, но становилось невыносимым, когда вывод отправлялся в ничего не подозревающий процесс. Тем не менее, не желая нарушать простоту стандартного ввода-вывода. стандартная модель вывода, люди терпели такое положение вещей до версии 6. Вскоре после этого Деннис Ритчи разорвал узел Гордиана, введя стандартный файл ошибок. Этого было недостаточно. С помощью конвейеров диагностика могла выполняться из любой из нескольких программ, работающих одновременно. Необходима диагностика идентифицировать себя ".


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 

Но для простого ответа каждый файл предназначен для:

стандартный поток для выхода

стандартный ввод потока

stderr для печати ошибок или сообщений журнала.

Каждая программа Unix имеет каждый из этих потоков.


2

stderr не будет выполнять буферизацию IO Cache, поэтому, если нашему приложению нужно вывести критическую информацию о сообщении (некоторые ошибки, исключения) на консоль или в файл, используйте ее, где, как и stdout, для печати общей информации журнала, так как она использует буферизацию IO Cache, есть вероятность, что перед записью наших сообщений в файл приложение может закрыться, оставив комплекс отладки


0

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.