pty
— 偽終端實用工具¶
原始碼: Lib/pty.py
pty
模組定義了處理偽終端概念的操作:啟動另一個程序,並能夠以程式設計方式寫入和讀取其控制終端。
可用性:Unix。
偽終端處理高度依賴於平臺。 此程式碼主要在 Linux、FreeBSD 和 macOS 上測試(它應該在其他 POSIX 平臺上工作,但尚未經過全面測試)。
pty
模組定義了以下函式
- pty.fork()¶
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]])¶
生成一個程序,並將其控制終端與當前程序的標準 io 連線。 這通常用於迷惑那些堅持從控制終端讀取的程式。預計在 pty 後生成的程序最終會終止,當它終止時 spawn 將返回。
一個迴圈將當前程序的 STDIN 複製到子程序,並將從子程序接收的資料複製到當前程序的 STDOUT。如果當前程序的 STDIN 關閉,則不會向子程序發出訊號。
函式 master_read 和 stdin_read 傳遞一個它們應該從中讀取的檔案描述符,並且它們應該始終返回一個位元組字串。為了強制 spawn 在子程序退出之前返回,應返回一個空位元組陣列以表示檔案結束。
這兩個函式的預設實現每次呼叫該函式時都會讀取並返回最多 1024 個位元組。 master_read 回撥傳遞偽終端的主檔案描述符以讀取子程序的輸出,而 stdin_read 傳遞檔案描述符 0,以從父程序的標準輸入讀取。
從任何一個回撥返回一個空位元組字串都被解釋為檔案結束 (EOF) 條件,並且在該條件之後不會呼叫該回調。 如果 stdin_read 發出 EOF 訊號,則控制終端將無法再與父程序或子程序通訊。除非子程序將在沒有任何輸入的情況下退出,否則 spawn 將永遠迴圈下去。如果 master_read 發出 EOF 訊號,也會導致相同的行為(至少在 Linux 上)。
返回子程序上
os.waitpid()
的退出狀態值。os.waitstatus_to_exitcode()
可用於將退出狀態轉換為退出程式碼。使用引數
argv
引發一個 稽核事件pty.spawn
。在 3.4 版本中更改:
spawn()
現在返回子程序上os.waitpid()
的狀態值。
示例¶
以下程式的作用類似於 Unix 命令 script(1),使用偽終端記錄終端會話的所有輸入和輸出,並將其記錄在“typescript”中。
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)