核心思路是通过subprocess.Popen配合逐行读取实现输出分流:实时打印到终端并同步捕获到内存列表,避免使用communicate()等阻塞方法。

用 subprocess 同时实时打印并捕获输出,核心思路是:不依赖 stdout=PIPE 的阻塞式读取,而是通过边读边写的方式,把子进程的输出流“分流”到终端和内存中。
用 subprocess.Popen + 迭代读取(推荐)
这是最可控、兼容性好、不依赖第三方库的方法。关键点在于:
- 设置
stdout=subprocess.PIPE和/或stderr=subprocess.PIPE - 使用
iter(p.stdout.readline, b'')或p.stdout.readline()逐行读取(避免阻塞或丢行) - 每读一行就立刻
print()到控制台,并追加到列表中保存 - 注意编码:默认字节流,需用
.decode('utf-8', errors='replace')安全转字符串
示例代码:
import subprocesscmd = ['python', '-c', 'print("hello"); print("world"); import time; time.sleep(1); print("done")'] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, universal_newlines=False)
stdout_lines = [] for line in iter(proc.stdout.readline, b''): decoded = line.decode('utf-8', errors='replace').rstrip('\n') print(decoded) # 实时打印 stdout_lines.append(decoded)
proc.wait() # 等待结束,确保所有输出已读完 print("全部捕获内容:", stdout_lines)
用 threading 分离读取与打印(适合多流/复杂场景)
当需要同时处理 stdout 和 stderr,且希望它们互不干扰(比如不同颜色打印),可用线程分别监听:
- 为每个流起一个线程,持续调用
readline() - 主线程等待进程结束,再合并结果
- 注意线程安全:用
threading.Lock或直接往 list 追加(list.append 是线程安全的)
小提示:避免用 read() 或 communicate() —— 它们会阻塞直到进程退出,无法做到“实时”。
用 tee 类似逻辑(Unix/Linux/macOS)
如果运行环境支持 shell,可借助 tee 命令把输出同时写入文件和 stdout,再用 Python 读取该文件:
- 临时创建一个
NamedTemporaryFile - 执行类似
cmd | tee temp.log - 主程序边运行边读取日志文件(需注意文件刷新和编码)
但此法跨平台差、有竞态风险,仅作备选,不推荐作为主力方案。
用第三方库 pwntools 或 pexpect(高级需求)
如果你在做渗透测试、CTF 或交互式程序自动化:
-
pexpect天然支持实时匹配、交互、超时控制,适合带 prompt 的命令 -
pwntools的process对象提供recvline()、recvuntil()等方法,输出自动显示且可捕获
例如用 pexpect:
import pexpect
child = pexpect.spawn('python -c "print(\'hi\'); print(\'bye\')"', encoding='utf-8')
child.logfile_read = sys.stdout.buffer # 实时打印到 stdout
output = child.read().decode() # 最终完整捕获
注意:这些库需额外安装,且引入了新依赖,简单脚本中不必引入。











