Главная Веб-разработка STDIN, STDOUT, STDERR и файловые дескрипторы: от ядра до Python.

STDIN, STDOUT, STDERR и файловые дескрипторы: от ядра до Python.

от admin

Разбираемся, как устроены STDIN, STDOUT, STDERR и файловые дескрипторы на примере Linux и Python. Что происходит, когда вы вызываете print()? Ответ — на трёх уровнях абстракции: ядро, C и Python.

029 открытий143 показов

Дисклеймер

У меня нет цели раскрыть данную тему целиком и очень точно во всех технических нюансах, так как я не являюсь системным програмистом или одареным гением.

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

При программировании на C или Python мы часто сталкиваемся с выводом и вводом данных в программу. Это происходит даже тогда, когда программисты начинают изучать новый язык и пишут свою первую программу Hello World!.

Вот только использование функционала сопряжено с тем, что разработчики ЯП предоставляют нам удобный уровень абстракции, чтобы не задумываться, как это работает на самом деле. И поэтому для многих не всегда понятна внутренняя “кухня” данных процессов. Дальнейшее рассмотрение функционала будет на примере ОС “Ubuntu”.

Погрузимся в детали работы

Давайте попробуем поработать с дескрипторами в Shell, непосредственно в самом Linux.

  1. С помощью команды cat можно читать данные из файла(cat file.txt) либо из клавиатуры(cat).
  2. С помощью команды echo можно отправлять данные в консоль для отображения(echo “Hello”), либо отправить данные в файл(echo "Hello" > file.txt).
  3. Если вдруг вы пытаетесь найти несуществующий файл, возникнет ошибка в консоли(ls nofile.txt). Еще ее можно перенаправить в файл(ls nofile.txt 2> error.txt). Обратите внимание, что здесь конкретно мы указываем, из какого файлового дескриптора брать информацию.

Когда вы запускаете какой-либо Python процесс, создаются сразу три файловых дескриптора — для ввода и вывода данных.

Анонсирована Аврора SDK для ARM-процессоров Apple Silicontproger.ru

Ниже прикреплен Python скрипт. Прежде чем запустить, давайте его разберем:

  1. Для получения данных извне мы можем использовать функцию input. О чем нам говорит строка документация функции: “Read a string from standard input.”
  2. Функция print по умолчанию отправляет данные в stdout, так как аргумент функции file по умолчанию — sys.stdout
  3. Изменить поток ввода на stderr возможно, явно передав объект из модуля sys, в аргумент file функции print. Сообщение об ошибке будет красным, прям так же, как и при ошибке, потому что они автоматически отправляются в поток STDERR уже на уровне интерпретатора.
			# main.py import sys  input_command = input("Enter your commandn") # STDIN print(f"Your command: {input_command}") # STDOUT print("Your command raising an exception: Some exception.", file=sys.stderr) # STDERR 		

Запуск скрипта

Теперь давайте попробуем запустить данный скрипт и найти наши файловые дескрипторы.

Сначала необходимо найти PID данного Python-процесса. Для этого открываем терминал и пишем команду ps aux | grep main.py.

Нас интересует вторая колонка, где указан PID. Для того чтобы получить файловые дескрипторы, необходимо ввести команду lsof -p YOUR_PID | grep FIFO.

Почему именно файловые дескрипторы используются для ввода и вывода данных?

Идеология Linux “Everything is a file“ говорит, что все есть файл. А для того чтобы работать унифицировано со всеми компонентами системы, были и введены дескрипторы.

Читать также:
Как разработать игру с помощью нейросетей: опыт креативного продюсера

Соответственно, это упрощает разработку программ, делает код компактным, переиспользуемым и предсказуемым.

Что на самом деле значит STDIN, STDOUT, STDERR и файловые дескрипторы?

Когда начинаешь размышлять про это все, можно и запутаться. Что это числа, потоки, файлы? Сначала разберемся с понятиями.

File Descriptor — Целое число, которое служит идентификатором для открытого файла(т.к. почти всё в Unix-подобных системах это файлы).

STDIN — Стандартный поток ввода, принадлежащий файловому дескриптору 0. Получает данные от клавиатуры или из файла/потока.

STDOUT — Стандартный поток вывода, принадлежащий файловому дескриптору 1. Отправляет данные на экран или в файл.

STDERR — Стандартный поток ошибок, принадлежащий файловому дескриптору 2. Отправляет данные на экран или в файл.

Рассмотрим на разных уровнях абстракции.

Уровень ядра / Низкий уровень абстракции

В операционных системах Unix-подобного типа всё есть файл, включая ввод и вывод, терминал, сетевые сокеты и тп.

Болевые точки Django в современной разработкеtproger.ru

Открывая файл, делая GET запрос, получая данные из БД, разработчики создают целочисленные идентификаторы т.е. файловые дескрипторы.

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

Вот пример, как можно перенаправлять данные из одного дескриптора в другой: echo "An error occurred: Some exception." 1>&2

Уровень C / Средний уровень абстракции

Удобным способом взаимодействия с вводом/выводом выступают потоки на уровне С. На этом уровне и написан Python интерпретатор.

Заметьте, тут уже нет и слов про дескрипторы, так как это абстракция над ними. Пример в C: fprintf(stderr, "An error occurred: Some exceptionn");

Уровень Python / Высокий уровень абстракции

В Python ввод/вывод представлены как TextIO объекты. Пример в Python:

			import sys  				print("An error occurred: Some exception.", file=sys.stderr) 		

Резюмируем: На уровне ОС STDIN, STDOUT, STDERR — это файлы, идентифицируются по дескрипторам. На уровне С STDIN, STDOUT, STDERR — это потоки. На уровне Python STDIN, STDOUT, STDERR — это TextIO объекты.

Понимание STDIN, STDOUT, STDERR и файловых дескрипторов критично для системного разработчика, который работает с консольными утилитами либо скриптами на уровне ОС. Поскольку на уровне системы нет синтаксического «сахара», который есть в ЯП. А прикладным программистам это необходимо знать для общей технической грамотности. Также это будет полезно знать, чтобы правильно настроить логирование приложения.

Если вам интересны такие темы — у меня есть канал, где я пишу о backend разработке.

Похожие статьи