如何捕获Python子进程的交错stdin与stdout输出?
还原Python子进程的交互式输入输出效果
问题场景
我正在开发一个自动批改学生Python脚本的工具,学生提交的脚本会用input()获取用户输入,示例如下:
name = input('Enter your name: ') print(f'Hello {name}!')
用subprocess.run()测试时,代码如下:
import subprocess run_cmd = 'python student_script.py' test_input = 'Bob' p = subprocess.run(run_cmd.split(), input=test_input, capture_output=True, text=True)
此时p.stdout捕获到的内容是:
'Enter your name: Hello Bob!\n'
但我需要还原命令行的交互效果,得到如下格式的输出:
'Enter your name: Bob\nHello Bob!\n'
由于学生脚本的提示和输出不固定,无法手动插入测试输入到捕获的stdout中,需要可靠的方法捕获交错的stdin与stdout。
解决方案
subprocess.run()的input参数是通过管道传递输入,这种环境下input()不会回显输入内容,所以无法捕获到输入的回显。要实现需求,需要用**伪终端(pty)**模拟真实的终端环境,让input()自动回显输入内容。
代码实现
import pty import os import subprocess def capture_interactive_session(cmd, input_str): # 创建伪终端主从设备 master_fd, slave_fd = pty.openpty() # 启动子进程,将标准IO绑定到伪终端 proc = subprocess.Popen( cmd, stdin=slave_fd, stdout=slave_fd, stderr=slave_fd, text=False # 先以字节流处理,避免编码问题 ) os.close(slave_fd) # 关闭子进程端的伪终端 # 发送输入(需添加换行符模拟回车) os.write(master_fd, (input_str + '\n').encode()) # 读取终端输出 output_chunks = [] while True: try: chunk = os.read(master_fd, 1024) if not chunk: break output_chunks.append(chunk.decode()) except OSError: break # 子进程结束后读取会抛出异常 proc.wait() os.close(master_fd) return ''.join(output_chunks) # 使用示例 if __name__ == '__main__': test_cmd = ['python', 'student_script.py'] test_input = 'Bob' interactive_output = capture_interactive_session(test_cmd, test_input) print(repr(interactive_output)) # 输出:'Enter your name: Bob\nHello Bob!\n'
原理说明
伪终端会模拟真实的命令行终端环境,当input()在终端环境中运行时,系统会自动回显用户输入的内容。通过将子进程的标准IO绑定到伪终端,我们就能捕获到完整的交互流程:提示信息 → 输入回显 → 脚本输出,完美还原命令行的交互效果。
内容的提问来源于stack exchange,提问作者Bob Loblaw
相关产品推荐
相关产品推荐

