35.8. "pty" --- 伪终端工具
**************************

**源代码:** Lib/pty.py

======================================================================

"pty" 模块定义了一些处理“伪终端”概念的操作：启动另一个进程并能以程序方
式在其控制终端中进行读写。

由于伪终端处理高度依赖于具体平台，因此此功能只有针对 Linux 的代码。 （
Linux 代码也可在其他平台上工作，但是未经测试。）

"pty" 模块定义了下列函数:

pty.fork()

   分叉。 将子进程的控制终端连接到一个伪终端。 返回值为 "(pid, fd)"。
   请注意子进程获得 *pid* 0 而 *fd* 为 *invalid*。 父进程返回值为子进
   程的 *pid* 而 *fd* 为一个连接到子进程的控制终端（并同时连接到子进程
   的标准输入和输出）的文件描述符。

pty.openpty()

   打开一个新的伪终端对，如果可能将使用 "os.openpty()"，或是针对通用
   Unix 系统的模拟代码。 返回一个文件描述符对 "(master, slave)"，分别
   表示主从两端。

pty.spawn(argv[, master_read[, stdin_read]])

   Spawn a process, and connect its controlling terminal with the
   current process's standard io. This is often used to baffle
   programs which insist on reading from the controlling terminal.

   The functions *master_read* and *stdin_read* should be functions
   which read from a file descriptor. The defaults try to read 1024
   bytes each time they are called.

   3.4 版更變: "spawn()" 现在会从子进程的 "os.waitpid()" 返回状态值。


35.8.1. 示例
============

以下程序的作用类似于 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)
