что такое терминал в python
Приступая к работе¶
Что тебе потребуется¶
Python!¶
Если у тебя ещё нет Python’а, ты можешь найти последние официальные установочные файлы здесь:
Будучи последним, Python 3 предпочтительнее!
И редактор кода¶
Sublime Text: простой, но проприетарный редактор, поддерживающий Windows, Mac и GNU/Linux. Сочетание клавиш Ctl+B запускает открытый файл.
Geany: простой в обращении и не перегруженный функциями редактор, работающий на Windows и GNU/Linux.
TextMate: один из самых известных редакторов кода для Mac’ов, изначально бывший коммерческим продуктом, но позже ставший свободным и бесплатным.
Gedit и Kate: если ты используешь GNU/Linux с Gnome или KDE соответственно, то один из них должен быть предустановлен!
Komodo Edit: неплохой свободный редактор под Mac, Windows и GNU/Linux, основанный на более мощной Komodo IDE.
Если ты хочешь последовать нашим рекомендациям, для начала попробуй Sublime Text.
Wordpad, TextEdit, Notepad и Word – неподходящие текстовые редакторы.
Всё же, что такое Python?¶
В действительности, Python – всего лишь ещё одна программа на твоём компьютере. Для начала нужно узнать, как использовать и взаимодействовать с ним. Существует много способов научиться этому, первый из которых – работать и интерпретатором Python, используя консоль операционной системы (ОС).
Консоль (“терминал”, “командная строка”) – это текстовый (в отличие от так называемых “окружений рабочего стола” (Desktop Environment, DE), работающих в связке с мышью) интерфейс для работы с ОС.
Открываем консоль в Mac OS X¶
Командная строка Terminal — это инструмент для “общения” с компьютером. Открывшееся окно должно содержать сообщение-подсказку, что-то вроде этого:
Открываем консоль в GNU/Linux¶
В дистрибутивах GNU/Linux (Ubuntu, Fedora, Mint и т.д.) обычно уже установлены разные программы-консоли, обычно называемые терминалами. То, какой терминал установлен, зависит от используемого дистрибутива. Например, в Ubuntu это Gnome Terminal. После запуска появляется приглашение вроде этого:
Открываем консоль в Windows¶
Командная строка Windows намного менее функциональна, чем её аналоги из GNU/Linux и OS X, потому лучше запускать интерпретатор Python’а (см. ниже) напрямую или с помощью программы IDLE, которая поставляется с Python’ом (найти её можно в меню “Пуск”).
Использование Python¶
Python-программа, установленная по умолчанию, называется интерпретатором. Интепретатор принимает команды и выполняет их после ввода. Очень удобно для тестирования чего-либо.
Чтобы запустить интерпретатор, просто введи python и нажми Enter.
Взаимодействие с Python’ом¶
Когда Python запустится, ты увидишь что-то вроде этого:
>>> в последней строке означает, что сейчас мы находимся в интерактивном интерпретаторе Python, также называемом “Оболочкой Python (Python shell)”. Это не то же самое, и что обычная командная строка!
Теперь ты можешь ввести немного Python-кода. Попробуй:
Нажми и посмотри, что произошло. После вывода результата Python вернёт тебя обратно в интерактивную оболочку, в которой мы можем ввести какую-нибудь другую команду:
Запуск файлов с Python-кодом¶
Когда Python-кода становится слишком много, лучше записывать его в файлы. Это, например, позволит тебе редактировать отдельные части кода (исправлять ошибки) и тут же запускать их без необходимости перепечатывать текст. Просто сохрани код в файл, и передай его имя python‘у. Записанный в файл исходный код будет выполнен без запуска интерактивного интерпретатора.
В Windows нужно два раза кликнуть на пиктограмму файла, чтобы запустить его.
Когда ты нажмешь в консоли, наш файл выполнится и результат его работы будет выведен на экран. В этот момент интерпретатор Python выполнит все инструкции, находящиеся в скрипте и вернет управление командной строке, а не интерактивной оболчке Python.
Теперь всё готово, и мы можем приступить к черепашке!
Вместо ожидаемого “Hello world” ты получил какие-то странные ошибки “can’t open file” или “No such file or directory”? Скорее всего, что ты работаешь не в той директории где сохранен твой Pyhton-скрипт. С помощью командной строки легко сменить текущий активный каталог, используя команду cd, что означает “change directory” (сменить каталог). В Windows эта команда может выглядеть так:
© Авторские права 2012–2014, OpenTechSchool and contributors.
Создано с помощью Sphinx 1.3.1.
Как запускать код на Python в терминале (Python Shell)
Дата: 20.03.2019 Категория: Python Комментарии: 0
Писать небольшие программы (скрипты, сценарии) на Python можно непосредственно в окне терминала. В операционных системах семейства Windows, функции терминала выполняет «командная строка» (command prompt). Для того чтобы ее открыть, нужно нажать сочетание клавиш Win + R, ввести команду cmd и нажать Enter.
С этого момента вы можете писать код на Python, завершая каждую строку нажатием клавиши Enter. Следует заметить, что нужно помнить про отступы после перехода на новую строку. Так, например, после ввода for i in range(10): и нажатия клавиши Enter, вы увидите что приглашение для ввода команд на новой строке изменилось на три точки (. ). Далее вам нужно либо нажать Tab либо ввести 4 пробела и только после этого начать писать следующую строку кода. Чтобы выйти из цикла и выполнить блок кода, нужно дважды нажать клавишу Enter.
В заключении стоит отметить что Python Shell и режим REPL не очень подходят для написания каких то программ. Даже для написания небольших сценариев удобней пользоваться IDLE или воспользоваться редактором кода.
Как запустить скрипт на Python
Каждый разработчик на Python должен знать, как запускать скрипты, потому что это единственный способ проверить работоспособность написанного кода. Чтобы запустить скрипт, программист может использовать:
Каждый способ имеет свои особенности, поэтому его выбор зависит не только от предпочтений или привычек, но и от того, в какой степени программист хочет контролировать параметры запуска скрипта.
Интерпретатор и его установка
Интерпретатор — это программное обеспечение, которое позволяет запускать скрипты Python. С технической точки зрения интерпретатор является связующим слоем между кодом на Python и машинным кодом.
Интерпретатор используется каждый раз, когда программист запускает код: в интерактивном режиме, через командную строку, всегда.
Если же у вас старая версия Windows и предыдущий вариант не работает, то надо зайти на официальный сайт Python, скачать и запустить установочный файл и следовать инструкциям по установке. Не забудьте при установке выставить галку, чтобы Python был добавлен в Windows PATH.
В Linux обычно ничего устанавливать не требуется, так как Pyton включают в его дистрибутив.
Интерактивный запуск кода Python
Для работы с маленькими кусками кода программисты часто используют режим интерактивного сеанса. В этом режиме введенный код на Python сразу интерпретируется и исполняется. То есть не нужно создавать файл и запускать его.
Чтобы войти в интерактивный режим в Windows, можно использовать один из нескольких способов:
Чтобы запустить интерактивный сеанс в Linux, необходимо выполнить в терминале команду «python3» или «python2».
Примеры работы в интерактивном сеансе
Интерактивный сеанс является необходимым и важным инструментом. С его помощью программист может быстро проверить код, в работе которого он не уверен.
Код исполняется сразу после ввода, однако это не значит, что в терминале можно использовать только однострочные операции, например:
В командной строке также можно писать функции, циклы, условия. Кроме того, в интерактивном сеансе можно импортировать модули.
Командная строка автоматически определяет, когда нужно написать многострочную инструкцию, например, если программист хочет объявить функцию, он пишет:
«>>>» — это просто отображаемый в командной строке символ, свидетельствующий о возможности ввода. Многоточие показывает, что ввод не закончен, тем самым разрешая программисту писать сложные конструкции в несколько строк.
Следующая команда вызывает только что созданную функцию:
Запуск скрипта Python через командную строку
Интерактивный сеанс позволяет тестировать код, но как только он завершится, весь код потеряется.
Поэтому большая часть кода пишется с использованием текстовых файлов, которые имеют расширение «.py». Они могут быть созданы с помощью любого текстового редактора, подойдет даже обычный блокнот.
Предположим, что наш скрипт выводит на экран надпись «Hello World!», то есть код будет следующим:
Запишем его в файл world.py. Запустить его через командную строку можно несколькими способами.
Команда «python» и запуск по имени
Самый простой и практичный запуск скриптов — использовать команду «python». Нужно открыть командную строку и написать «python имя_скрипта». Важно, чтобы скрипт находился либо в директории, из которой запущена командная строка, либо в каталоге, прописанном в переменной среды PATH. Тогда запуск пройдет успешно:
Если на компьютере установлены две версии Python, (а на Linux обычно так и есть) следует использовать команды «python3» и «python2» для вызова соответствующей версии.
В последних версиях Windows можно запустить скрипт Python просто введя его имя:
В этом случае запустится новая консоль, выведется в неё сообщение и закроется. Мы ничего не успеем увидеть. Чтобы этого не было, можно в конец файла добавить input(), чтобы скрипт ожидал ввода пользователя.
Такой запуск возможен благодаря тому, что Windows автоматически определяет, какую программу (в данном случае интерпретатор Python) использовать для запуска файла.
В Linux также можно воспользоваться этим способом, но в начале скрипта Python в первой строке должен быть указан полный путь к интерпретатору:
После этого нужно разрешить запуск файла (сделать его исполняемым).
Теперь достаточно просто запустить скрипт, введя в терминал его имя, перед которым добавить «./»:
Запуск модуля
Иногда возникает необходимость запустить модуль, как скрипт. Однако при использовании обычного способа командная строка выдает предупреждение о том, что файл нельзя открыть.
Чтобы запустить модуль, как исполняемый файл, нужно воспользоваться командой:
Перенаправление вывода
Если результаты выполнения скрипта нужно где-то сохранить, чтобы использовать их в последующих операциях, программист может перенаправить вывод из консоли в, например, файл. Для этого используется оператор «>». Вернём содержимое нашего файла world.py в изначальный вариант:
Теперь запустим. Полная команда выглядит так:
Здесь output.txt – это текстовый файл, в который записывается результат выполнения скрипта.
Операция может использоваться как в операционной системе Windows, так и в Unix-подобных системах. Если файла, в который должен вывестись результат, не существует, система создаст его автоматически.
При использовании оператора «>» содержимое файла, в который выводятся данные, полностью перезаписывается. Если уже имеющиеся данные нужно сохранить, используют оператор «>>».
Например, у нас уже есть файл output.txt со строкой приветствия (после того как мы его создали предыдущей командой). Теперь допишем в него ещё одну строку:
Таким образом можно последовательно запустить несколько раз этот скрипт и в файл будут дописываться всё новые строки приветствия.
Использование IDLE
IDLE – это официальная интегрированная среда разработки, поставляемая вместе с интерпретатором Python.
Она позволяет работать в интерактивном режиме, писать и запускать скрипты. Кроме того, IDLE поддерживает подсветку синтаксиса и отладку.
Работа в интерактивном режиме не отличается от того, что было описано для командной строки Windows и терминала Linux. Программист пишет код, который сразу исполняется интерпретатором.
Запуск скрипта
Запуск скрипта из интерактивного режима
Иногда при работе в интерактивном режиме возникает необходимость проверить код какого-либо скрипта. Не обязательно использовать терминал или отдельно открывать скрипт в IDLE, его можно запустить прямо из интерактивного сеанса различными способами.
import
При импорте модуля в скрипт выполняется весь содержащийся в нём код. Если модуль содержит только объявления функций и классов и присвоение значений, программист ничего не увидит. Но если модуль выводит что-то на экран, работает с файлами, то это отобразится при импорте.
Таким образом можно импортировать модуль в интерактивном режиме, чтобы увидеть результаты его выполнения, однако сделать это можно только один раз, потому что при последующих импортах в пределах одного сеанса ничего не произойдет, так как при каждом новом импорте интерпретатор обращается к модулю, записанному в кэш, а не к реальному файлу.
Здесь импортировал библиотеку sys для того чтобы в пути прописать полный путь до моего модуля. Видно, что приветствие отображается только после первой попытки импорта моего модуля.
Оператор exec() сначала читает содержимое модуля, затем отправляет его в функцию, которая выполняет код.
Синтаксис выглядит так:
Запуск скриптов из текстового редактора или IDE
Если программист работает над крупным проектом, ему не достаточно стандартной IDLE и блокнота. В этом случае используется либо текстовый редактор, либо полноценная среда разработки IDE.
Для большинства текстовых редакторов разработаны плагины, позволяющие запускать скрипты Python одним кликом мыши. Сейчас очень популярен текстовый редактор VS Code. Вот здесь можно описано как с ним работать.
Большинство IDE поддерживают запуск скриптов по умолчанию. Обычно это делается с помощью встроенной в панель инструментов кнопки «Запуск/отладка». Эту функцию поддерживают такие IDE, как Eclipse, PyCharm, Eric, NetBeans и другие.
Запуск скриптов через менеджер файлов
В любой операционной системе с графическим интерфейсом можно запустить скрипт Python двойным кликом по файлу. Однако здесь есть свои нюансы, во-первых, система должна связывать расширение «.py» с интерпретатором Python, во-вторых, такой способ ограничивает программиста, не позволяя указать дополнительные параметры.
Этот способ можно использовать не только в Windows, но и Unix-подобных системах. Однако после запуска окно консоли будет сразу закрываться. Чтобы решить эту проблему, в конце скрипта добавляется оператор input(), таким образом консоль не закроется, пока не получит ввод от пользователя.
Ещё одной проблемой является невозможность обнаружения и отладки ошибок. Даже если программист добавил оператор input(), при возникновении ошибки в процессе выполнения скрипта консоль закроется.
Это самый ненадёжный способ, который накладывает на программиста много ограничений. Лучше отказаться от идеи пользоваться файловым менеджером во время отладки скриптов и вернуться к стандартным способам запуска через командную строку.
Как запустить программу Python – 4 простых способа
Программисты Python должны знать все возможные способы запуска сценариев или кода Python. Это единственный способ проверить, работает ли код так, как мы хотим. Интерпретатор Python отвечает за выполнение скриптов Python.
Что такое интерпретатор в Python?
Интерпретатор в Python – это часть программного обеспечения, которое взаимосвязано работает между программой Python и компьютерным оборудованием.
Здесь мы описываем серию способов запуска скриптов Python.
Командная строка операционной системы или терминал
Мы пишем оператор печати Python и сохраняем его как sample.py в рабочем каталоге. Теперь мы запустим этот файл из командной строки.
Откройте командную строку, чтобы запустить скрипт Python. Нам нужно ввести python, а затем имя файла для выполнения файла. Теперь нажмите клавишу ввода, и если в файле нет ошибки, мы увидим следующий результат.
Интерактивный режим Python
Чтобы запустить код Python, мы можем использовать интерактивный сеанс Python. Для запуска интерактивного сеанса Python, просто откройте командную строку или терминал в меню «Пуск», затем введите python и нажмите клавишу ввода.
Вот пример того, как запустить код Python с помощью интерактивной оболочки.
Это позволяет нам проверять каждый фрагмент кода, и это средство делает его отличным инструментом разработки. Но как только мы закроем сеанс, он потеряет весь написанный нами код.
Ниже приведены варианты выхода из интерактивного режима.
IDE или текстовый редактор
IDE означает интегрированную среду разработки. Существуют различные IDE, но Pycharm – самый популярный и полезный текстовый редактор Python среди них. Рекомендуется для разработки больших и более сложных приложений. Здесь используется Pycharm для запуска скрипта Python.
Теперь нажмите зеленую кнопку, и результат отобразится следующим образом.
Hello, World! Глубокое погружение в Терминалы
На написание данной статьи меня вдохновила статья об анализе Сишного printf. Однако, там был пропущен момент о том, какой путь проходят данные после того, как они попадают в терминальное устройство. В данной статье я хочу исправить этот недочет и проанализировать путь данных в терминале. Также мы разберемся, чем отличается Terminal от Shell, что такое Pseudoterminal, как работают эмуляторы терминалов и многое другое.
Основы
Давайте для начала разберемся, что такое Terminal, Shell, Console, чем отличается Terminal Emulator от обычного Terminal и почему он так назван. Информации об этом написано уже довольно много, поэтому ничего нового вы здесь не услышите. Почти вся информация здесь была взята из интернета, ссылки приведу в конце статьи. Кто уже знает, что все эти вещи обозначают, может смело пропускать данный раздел.
Terminal
Terminal (терминал) — это комбинация дисплея и клавиатуры, то есть физическое устройство. До того, как терминалы стали именно данной комбинацией, они являлись неким устройством под названием teleprinter (teletype, teletypewriter или TTY сокращенно), то есть комбинацией принтера и клавиатуры. Обычно несколько терминалов подключались к одному и тому же компьютеру. Таким образом возможно было работать нескольким пользователям за одним и тем же компьютером, причем каждому выделялась своя сессия, независимая от других. Терминал был назван так потому, что он находился на конце терминального кабеля (terminal end).
Это Teletype:
А это Terminal:
Console
Console (консоль) — терминал, который подключен напрямую к компьютеру. Дело в том, что большинство терминалов были соединены неявно, но хотя бы один был подключен напрямую к компьютеру. Консоль было разрешено использовать строго определенному кругу лиц, так как она позволяла настраивать компьютер.
Shell
Если предыдущие два представляют собой физические устройства, то данное определение относится исключительно к программному обеспечению.
Shell — это command line interpreter. Главное предназначение — запускать другие программы. Существует большое количество различных Shell’ов. Самым распространенным является Bash (от англ. Bourne Again SHell, что как подсказывает Википедия, является каламбуром для «Born again» Shell, то есть «возрождённый» Shell). Другие примеры: Dash (легковесный Shell, доступен, если запустить бинарник по адресу /bin/sh), Zsh.
Конечно же, и терминалы, и консоли не могли не найти своего отражения в современности. Поэтому далее мы рассмотрим такие вещи, как Terminal Emulator и Virtual Console.
Terminal Emulator
Terminal Emulator — эмулятор старого доброго терминала. Эмулятор терминала требуется для программ, которые не могут напрямую взаимодействовать с X Window System — Bash, Vim и прочие.
Давайте для начала установим обязанности терминала:
Так и наш Terminal Emulator выполняет абсолютно то же самое: он доставляет ввод пользователя в запущенную программу, а также отображает вывод программы на дисплей. В любом случае, смысл сохраняется — между пользователем и запущенной программой, существует какой-то слой, отвечающий за ввод/вывод. Примеры Terminal Emulator: gnome-terminal, xterm, konsole.
Прошу не путать Shell и Terminal Emulator!
Terminal Emulator — GUI приложение, то есть окно в X Window System. Shell — это command line interpreter, то есть просто исполнитель команд, он не имеет графической оболочки. Если говорить совсем правильно, вы не запускаете Bash, вы запускаете Terminal Emulator, который запускает внутри себя Bash. Terminal Emulator и Bash — абсолютно 2 различные программы. Первая отвечает исключительно за ввод/вывод, вторая — за обработку команд.
Далее в статье все упоминания терминала будут относиться к эмулятору терминала.
Virtual Console (Virtual Terminal)
Нажмите Ctrl+Alt+FN, где N, обычно, имеет значения от 1 до 6. То, что вы сейчас видели — называется Virtual Console (виртуальная консоль) или Virtual Terminal (виртуальный терминал). Помните, что я говорил ранее о терминалах? Множество терминалов были подсоединены к одному компьютеру и каждый терминал был отдельной сессией, независимой от других. Virtual Console повторяет эту идею: внутри вашего компьютера может быть несколько независимых сессий (однако, ресурсы компьютера все же, очевидно, общие).
Вы можете именовать данную сущность как Virtual Console, так и Virtual Terminal, так как по определению, консоль — это терминал, подключенный напрямую к компьютеру, но ведь все виртуальные терминалы в каком-то смысле подключены напрямую к компьютеру.
TTY устройства
Каждому терминалу назначается свое TTY устройство (терминальное устройство), которое обеспечивает работу консоли. Хотя телетайпы вы вряд ли уже найдете, но сокращение TTY дошло и до наших дней.
TTY устройство состоит из двух фундаментальных компонентов:
Строение TTY устройства:
Существует 3 типа TTY устройств:
В данной статье мы будем говорить именно о втором типе TTY устройств — псевдотерминалах.
TTY Line Discipline
Начнем рассматривать дисциплину линии TTY устройств.
Первой важной особенностью дисциплиной линии является то, что она отвечает за процессинг ввода/вывода. Это включает в себя, например, обработку управляющих символов (см. Управляющие символы) и форматирование вывода. Например, вы вводите любой текст, но вдруг понимаете, что ошиблись в написании чего-то и хотите это стереть — именно тут в дело вступает дисциплина линии.
Разберем подробно, что именно происходит, когда мы работаем в Bash, запущенном в терминале. По умолчанию TTY устройство работает в каноничном режиме с включенным эхо (echoing). Эхо — это отображение введенных вами символов на экране.
TTY Line Editing
TTY Line Editing — это тот компонент, который отвечает за процессинг ввода в дисциплине линии. Следует сказать, что Line Editing — это общее понятие и относится оно к процессингу ввода. Например, Bash и Vim имеют свой Line Editing.
Мы можем контролировать настройки дисциплины линии текущего TTY устройства с помощью программы stty. Давайте немного поэкспериментируем.
Откройте Bash или любой другой Shell и введите:
Теперь попробуйте что-нибудь ввести — и вы не увидите вашего ввода (не беспокойтесь, вы все еще можете передавать ввод в программу). Вы только что отключили эхо — то есть отображение введенных символов на экране. Теперь введите:
Больше информации вы сможете найти в man stty.
Terminal Emulator и Pseudoterminal
Каждый раз, когда мы открываем новый терминал в X Window System, GNOME Terminal Server порождает новый процесс и запускает в нём выбранную по умолчанию программу. Обычно, это какой-то Shell (например, Bash).
Общение с запущенной программой происходит через так называемый Pseudoterminal (псевдотерминал, PTY). Сам псевдотерминал существует в ядре, однако ввод получает из пользовательского пространства — из эмулятора терминала.
Псевдотерминал состоит из следующих двух виртуальных TTY устройств:
1) PTY master (PTM) — ведущая часть псевдотерминала. Используется GNOME Terminal Server для передачи ввода с клавиатуры в запущенную внутри терминала программу, а также для чтения вывода программы и отображения вывода на дисплей. GNOME Terminal Server в свою очередь общается с X Window System по X протоколу.
2) PTY slave (PTS) — ведомая часть псевдотерминала. Используется программой, запущенной внутри терминала, для чтения ввода с клавиатуры и отображения вывода на экран. По крайней мере, так думает сама программа (объясню, что это значит, чуть далее).
Любые данные, записанные в PTS устройство, являются вводом PTM устройства, то есть становятся доступны для чтения на PTM устройстве. И наоборот: любые данные, записанные в PTM устройство, являются вводом PTS устройства. Именно таким образом и происходит общение GNOME Terminal Server и запущенной внутри терминала программы. Каждому PTM устройству сопоставляется свое PTS устройство.
Помните, я сказал, что программа, использующая PTS устройство, только думает, что она общается напрямую с терминалом? Дело в том, что PTS также является терминальным устройством (TTY устройством), но разница между PTS устройством и действительным TTY устройством в том, что PTS устройство ввод получает не с клавиатуры, а с master устройства, а вывод идет не на дисплей, а на master устройство. Именно поэтому псевдотерминал назван так — псевдотерминал лишь имитирует (опять??) терминал. Разница между эмулятором терминала и псевдотерминалом в том, что эмулятор терминала — это лишь графическая программа, позволяющая запускать терминал прямо внутри оконного интерфейса, но реализована эта возможность с помощью псевдотерминала.
То, что PTS устройство является TTY устройством — это очень важно. Вот почему:
PTM устройство также является TTY устройством, но это не играет никакой роли, так как оно не используется в роли управляющего терминала. Более того, дисциплина линии PTM устройства установлена в raw режим, поэтому процессинг при передаче данных от PTS к PTM устройству не производится. Однако, вызовы read() и write() из пользовательского пространства все равно сперва обслуживаются дисциплиной линии на обоих устройствах. Данный момент сыграет еще большую роль, как мы увидим позднее.
Процесс общения GNOME Terminal Server и запущенной внутри терминала программы выглядит следующим образом:
Следует поподробнее рассмотреть роль, которую играет дисциплина линии при общении между обеими частями псевдотерминала. Здесь дисциплина линии отвечает за процессинг данных, переходящих от PTM к PTS устройству, а также за доставку данных из одной части псевдотерминала в другую. Когда мы находимся в драйвере PTS устройства, мы задействуем дисциплину линии PTM устройства, и наоборот.
Виртуальные устройства
Вы, наверное, могли подумать, что можете открыть файл по пути /dev/pts/N и писать или читать данные из него, как из обычного текстового файла? Да, все устройства в Unix-подобных системах являются файлами благодаря фундаментальному принципу Unix, который гласит, что все является файлом. Однако, никакие специальные файлы устройств (англ. — device file) не являются текстовыми файлами. Такие устройства называются виртуальными устройствами (virtual device) — то есть существуют исключительно в памяти, а не на диске.
Устройство псевдотерминала
Мы все ближе приближаемся к заключительной части статьи, но перед этим заглянем «под капот» Linux — рассмотрим устройство псевдотерминала на уровне ядра. Будет много кода, но я постараюсь объяснять каждый приведенный блок кода максимально подробно, сокращать неважные детали и идти последовательно.
Перед началом введем так называемую «корзину компонентов». По мере продвижения по ядру, мы будет добавлять в нее всё больше компонентов и находить связь между ними. Надеюсь, это еще лучше поможет понять устройство псевдотерминала. Приступим.
Когда Linux запускается, он загружает необходимые драйверы устройств. Такой драйвер имеется и у нашего псевдотерминала. Его регистрация начинается с вызова данной функции:
Для всех современных систем будет вызвана функция unix98_pty_init() :
Здесь нас интересует 3 вещи:
1. tty_set_operations
Функция tty_set_operations() всего лишь устанавливает таблицу функций для текущего драйвера:
Структура tty_operations — это таблица функций, которая используется для доступа к функциям драйвера TTY устройства.
Здесь можете наблюдать уже знакомую по статье о Сишном printf функцию pty_write — к ней мы вернемся чуть позднее.
Давайте добавим данную структуру в нашу корзину компонентов:
2. ptmx_open
Теперь перейдем к ptmx_open():
Сначала разберем функцию alloc_tty_struct() :
Единственное, что нас здесь интересует, это функция tty_ldisc_init() :
Которая вызывает tty_ldisc_get() :
Вроде бы ничего сложного? Давайте добавим все рассмотренные до этого момента структуры в нашу корзину и свяжем их таким же образом, как они связаны в коде:
Но мы создали tty_struct всего лишь для PTM устройства. А что же о PTS устройстве? Для этого вернемся к функции tty_init_dev() и вспомним о том, что дальше нас ожидает вызов функции tty_driver_install_tty() :
Комментарий подсказывает нам, что данный метод ответственен за создание различных дополнительных структур. PTS устройство и будет являться нашей дополнительной структурой. Признаюсь, это было для меня крайне удивительно, ибо это, черт возьми, целое устройство, а не просто какая-то дополнительная структура! Но мы то с вами понимаем, что все устройства — это всего лишь какие-то структуры, так что идем дальше. Хорошо, что такое здесь driver->ops->install? Для этого посмотрим на таблицу функций для PTM драйвера ещё раз:
И поймем, что нас интересует функция pty_unix98_install() :
Которая вызывает функцию pty_common_install() :
Мы видим, что для PTS устройства создается абсолютно такая же структура tty_struct за исключением того, что в ней будет находиться драйвер PTS устройства. Обе структуры хранят указатели друг на друга для общения между собой. Добавляем tty_struct для PTS устройства в нашу корзину.
Регистрация драйвера
Мы не будем рассматривать весь процесс регистрации драйвера, так как нас интересует только установка таблицы функций для файла TTY устройства (ведь мы должны как-то получить доступ к самому устройству при работе с файлом?).
Это — таблица функций, которая будет установлена для файла как PTM, так и PTS устройства:
Мы не будем добавлять данную структуру в нашу корзину, ибо она в принципе то и не относится к устройству псевдотерминалов и служит лишь для доступа к TTY устройству.
Готово. Мы рассмотрели процесс создания обоих устройств, который будет произведен при открытии мультиплексора /dev/ptmx. Таким образом, включая второе PTS устройство, которое имеет точно такое же строение, как и PTM устройство, общая картина строения псевдотерминала складывается следующая:
Hello, World!
Ну вот мы и подошли к самому главному. В данной главе мы полностью разберем путь нашей строки «Hello, World!», отправленной из простой Си программы в терминальное устройство.
Итак, наша строка «Hello, World!» отправляется в увлекательное путешествие. На самом деле, программа не знает ничего, кроме того, что она пишет в стандартный поток вывода. Ей больше нет разницы, куда этот вывод пойдет. Направьте stdout в /dev/null — и вывод вообще не будет нигде отображаться. Здесь я не буду рассказывать о вызовах библиотечных Си функций, а начнем сразу с файловой системы Linux.
Так как каждое устройство в Unix является файлом с определенными для него функциями write(), read(), close() и прочими, то при вызове write() на /dev/pts/0 мы попадаем в общую для всех файлов функцию __vfs_write() :
Здесь мы вызываем операцию write() из таблицы функций для текущего файла. Как вы помните, таблица функций была установлена при регистрации драйвера и выглядела она следующим образом:
Данная функция получает структуру tty_struct для текущего файла TTY устройства, а потом достает из нее дисциплину линии и вызывает функцию write() для нее. Таблица функций дисциплины линии выглядела следующим образом:
Переходим к функции n_tty_write() :
Итак, строка «Hello, World!» наконец отправилась в write() функцию драйвера PTS устройства. Найдем эту функцию в таблице функций драйвера:
Давайте здесь остановимся и проследим наш путь до этого места:
Вроде бы ничего не упустили. Итак, буфер передается в очередь ввода на PTM устройство. Разберемся, как именно это происходит.
Для начала, следует познакомить вас с новой структурой данных под названием flip buffer. Flip buffer — это структура данных, состоящая из двух массивов. Когда tty driver получает новые данные, он сохраняет их в первом массиве. Когда массив заполняется, ожидающая данных сторона будет об этом уведомлена и сможет прочитать данные из этого массива. Если в будущем появятся новые данные, они сохранятся уже во второй массив для того, чтобы не перезаписать читающиеся другой стороной данные. Когда и этот массив заполняется, ожидающая данных сторона снова будет уведомлена, а новые данные в следующий раз будут снова записываться в первый массив. Именно из-за такой логики данная структура данных и названа flip buffer — потому что данные перемещаются между массивами (наверное, здесь лучше подойдет какое-то другое слово, но я не знаю хорошего перевода для слова flip).
На самом деле, flip buffer был замёнен новой имплементацией в новых версиях ядра, однако поведение буфера осталось почти таким же, а все функции остались совместимы с раннее реализованными драйверами. Не стоит сильно вникать в устройство данного буфера, ясно одно — в конце концов данные будут перемещены в PTM устройство, а после окончания записи ожидающая сторона будет уведомлена о готовых для чтения данных.
Итак, наша строка «Hello, World!» оказалась в PTM устройстве. В это время GNOME Terminal Server заблокирован на вызове poll() (техника мультиплексирования I/O) и ожидает новых данных на любом из master устройств. Вы думаете, сейчас он проснется и прочитает новые данные на устройстве? Как бы не так. Когда я говорил об ожидающей стороне, я говорил о дисциплине линии, ведь это именно её задача — принимать ввод и производить его процессинг при необходимости.
Дисциплина линии будет уведомлена о новых данных с помощью вызова функции tty_flip_buffer_push() (в том же pty_write):
Я не знаю, что здесь подразумевается под work (предположу, что это какая-то внутренняя структура ядра для планировки различных задач) и какой компонент ядра отвечает за планировку, но из комментариев ясно следующее — когда задача начнет выполняться, доставку организует функция flush_to_ldisc() :
Все функции, начинающиеся с n_tty_receive_buf (кроме тех, где есть суффикс _raw) производят процессинг данных и записывают данные в буфер под названием read_buf, который и является основным буфером для чтения с TTY устройства. Так как дисциплина линии для PTM устройства установлена в raw режим, то процессинг не будет произведен и данные сразу запишутся в read_buf. Однако, если бы мы разбирали доставку данных от PTM к PTS устройству, то процессинг был бы произведен.
Опишу полную цепочку вызовов до конечного вызова, включая пропущенные вызовы:
Заметьте, никакая функция PTM драйвера при перемещении данных не была использована — вся работа произошла в дисциплине линии и драйвере PTS устройства.
Таким образом, наша строчка «Hello, World!» проходит следующий путь:
Заключение
Подведем итог. В данной статье мы узнали:
На этом все, спасибо за внимание! Если у вас возникли какие-нибудь вопросы — смело задавайте их в комментариях, буду рад ответить!