что такое терминальное окно в питоне
Как запускать код на 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, может храниться в редакторе кода, IDE или файле. И он не будет работать, если не знать, как его правильно запускать.
В этом материале рассмотрим 7 способов запуска кода, написанного на Python. Они будут работать вне зависимости от операционной системы, среды Python или местоположения кода.
Где запускать Python-скрипты и как?
Python-код можно запустить одним из следующих способов:
Запуск Python-кода интерактивно
Для запуска интерактивной сессии нужно просто открыть терминал или командную строку и ввести python (или python3 в зависимости от версии). После нажатия Enter запустится интерактивный режим.
Вот как запустить интерактивный режим в разных ОС.
Интерактивный режим в Linux
Откройте терминал. Он должен выглядеть приблизительно вот так :
После нажатия Enter будет запущен интерактивный режим Python.
Интерактивный режим в macOS
На устройствах с macOS все работает похожим образом. Изображение ниже демонстрирует интерактивный режим в этой ОС.
Интерактивный режим в Windows
Запуск Python-скриптов в интерактивном режиме
В таком режиме можно писать код и исполнять его, чтобы получить желаемый результат или отчет об ошибке. Возьмем в качестве примера следующий цикл.
Для выхода из интерактивного режима нужно написать следующее:
И нажать Enter. Вы вернетесь в терминал, из которого и начинали.
Есть и другие способы остановки работы с интерактивным режимом Python. В Linux нужно нажать Ctrl + D, а в Windows — Ctrl + Z + Enter.
Стоит отметить, что при использовании этого режима Python-скрипты не сохраняются в локальный файл.
Как выполняются Python-скрипты?
Отличный способ представить, что происходит при выполнении Python-скрипта, — использовать диаграмму ниже. Этот блок представляет собой скрипт (или функцию) Python, а каждый внутренний блок — строка кода.
При запуске скрипта интерпретатор Python проходит сверху вниз, выполняя каждую из них. Именно таким образом происходит выполнение кода.
Но и это еще не все.
Блок-схема выполнения кода интерпретатором
Это набор инструкций, которые приводят к финальному результату.
Иногда полезно изучать байткод. Если вы планируете стать опытным Python-программистом, то важно уметь понимать его для написания качественного кода.
Это также пригодится для принятия решений в процессе. Можно обратить внимание на отдельные факторы и понять, почему определенные функции/структуры данных работают быстрее остальных.
Как запускать Python-скрипты?
Для запуска Python-скрипта с помощью командной строки сначала нужно сохранить код в локальный файл.
Возьмем в качестве примера файл, который был сохранен как python_script.py. Сохранить его можно вот так:
Сохранить скрипт в текстовом редакторе достаточно легко. Процесс ничем не отличается от сохранения простого текстового файла.
Но если использовать командную строку, то здесь нужны дополнительные шаги. Во-первых, в самом терминале нужно перейти в директорию, где должен быть сохранен файл. Оказавшись в нужной папке, следует выполнить следующую команду (на linux):
После нажатия Enter откроется интерфейс командной строки, который выглядит приблизительно следующим образом:
Теперь можно писать код и с легкостью сохранять его прямо в командной строке.
Как запускать скрипт в командной строке?
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!» проходит следующий путь:
Заключение
Подведем итог. В данной статье мы узнали:
На этом все, спасибо за внимание! Если у вас возникли какие-нибудь вопросы — смело задавайте их в комментариях, буду рад ответить!