pty
— Псевдотерминальные утилиты¶
Исходный код: Lib/pty.py
Модуль pty
определяет операции для работы с концепцией псевдотерминала: запуск другого процесса и возможность программной записи в управляющий терминал и чтения с него.
Availability: Unix.
Обработка псевдотерминала сильно зависит от платформы. Этот код в основном тестировался на Linux, FreeBSD и macOS (предполагается, что он будет работать на других платформах POSIX, но он не был тщательно протестирован).
Модуль pty
определяет следующие функции:
- pty.fork()¶
Вилка. Подключите дочерний управляющий терминал к псевдотерминалу. Возвращаемое значение равно
(pid, fd)
. Обратите внимание, что дочерний модуль получает pid 0, а fd является недопустимым. Возвращаемое родительским значением является pid дочернего элемента, а fd - это файловый дескриптор, подключенный к управляющему терминалу дочернего элемента (а также к стандартным входным и выходным данным дочернего элемента).Предупреждение
В macOS использование этой функции небезопасно в сочетании с использованием системных API более высокого уровня, включая использование
urllib.request
.
- pty.openpty()¶
Откройте новую пару псевдотерминалов, используя
os.openpty()
, если возможно, или код эмуляции для универсальных систем Unix. Верните пару файловых дескрипторов(master, slave)
для главного и подчиненного конца соответственно.
- pty.spawn(argv[, master_read[, stdin_read]])¶
Запустите процесс и подключите его управляющий терминал к стандартному интерфейсу ввода-вывода текущего процесса. Это часто используется, чтобы сбить с толку программы, которые настаивают на считывании данных с управляющего терминала. Ожидается, что процесс, запущенный за pty, в конечном итоге завершится, и когда это произойдет, spawn вернется.
Цикл копирует стандартный ввод текущего процесса в дочерний, а данные, полученные от дочернего, - в стандартный вывод текущего процесса. Дочерний процесс не получает сигнала, если стандартный ввод текущего процесса завершается.
Функциям master_read и stdin_read передается файловый дескриптор, из которого они должны выполнять чтение, и они всегда должны возвращать строку байтов. Чтобы принудительно запустить spawn до завершения дочернего процесса, необходимо вернуть пустой массив байтов, чтобы указать конец файла.
Реализация по умолчанию для обеих функций будет считывать и возвращать до 1024 байт при каждом вызове функции. Обратному вызову master_read передается главный файловый дескриптор псевдотерминала для чтения выходных данных дочернего процесса, а stdin_read передается файловый дескриптор 0 для чтения из стандартного ввода родительского процесса.
Возврат пустой байтовой строки из любого из обратных вызовов интерпретируется как условие завершения файла (EOF), и после этого обратный вызов вызываться не будет. Если сигналы stdin_read управляющего терминала больше не могут взаимодействовать с родительским или дочерним процессом. Если дочерний процесс не завершит работу без каких-либо входных данных, spawn будет выполнять цикл вечно. Если master_read сигнализирует об аналогичных результатах поведения (по крайней мере, в Linux).
Возвращает значение статуса завершения из
os.waitpid()
для дочернего процесса.os.waitstatus_to_exitcode()
может использоваться для преобразования статуса выхода в код выхода.Создает auditing event
pty.spawn
с аргументомargv
.Изменено в версии 3.4:
spawn()
теперь возвращает значение состояния изos.waitpid()
для дочернего процесса.
Пример¶
Следующая программа действует подобно команде Unix script(1), используя псевдотерминал для записи всех входных и выходных данных сеанса терминала в «машинописном виде».
import argparse
import os
import pty
import sys
import time
parser = argparse.ArgumentParser()
parser.add_argument('-a', dest='append', action='store_true')
parser.add_argument('-p', dest='use_python', action='store_true')
parser.add_argument('filename', nargs='?', default='typescript')
options = parser.parse_args()
shell = sys.executable if options.use_python else os.environ.get('SHELL', 'sh')
filename = options.filename
mode = 'ab' if options.append else 'wb'
with open(filename, mode) as script:
def read(fd):
data = os.read(fd, 1024)
script.write(data)
return data
print('Script started, file is', filename)
script.write(('Script started on %s\n' % time.asctime()).encode())
pty.spawn(shell, read)
script.write(('Script done on %s\n' % time.asctime()).encode())
print('Script done, file is', filename)