Python 脚本控制 Linux 上的外部应用程序,通过管道将输入传递到外部应用程序标准输入,并通过管道从外部应用程序标准输出读取输出。
问题是对管道的写入是按块而不是按行缓冲的,因此在控制脚本接收数据输出之前会发生延迟,例如外部应用程序中的 printf。
无法更改外部应用程序以添加显式 fflush(0) 调用。
python标准库的pty模块如何配合subprocess模块来实现呢?
您可以使用 PTY 通过以下方式解决此问题:
这样做是可能的,但我能想到的唯一解决方案是相当复杂、不可移植,并且可能充满有问题的细节。您可以使用 LD_PRELOAD 使外部应用程序加载动态库,该动态库包含调用 setvbuf 以取消缓冲标准输出的构造函数。您可能还希望在库中包装 setvbuf 以防止应用程序显式缓冲其自己的标准输出。而且您需要包装 fwrite 和 printf 以便它们在每次调用时刷新。编写要预加载的 .so 将使您脱离 python。
我不认为这是可能的。如果源应用程序不刷新其传出缓冲区,则数据将不会到达该进程之外,直到缓冲区溢出并强制刷新。
请注意,诸如file之类的完善命令如何具有一个选项 (-n),使其显式刷新其输出。在从管道读取输入文件名并打印检测到的类型的模式下使用文件时,这是必需的。由于在此模式下,文件程序在完成后不会退出,否则不会出现输出。
在较低的层次上考虑这一点:输出缓冲仅仅意味着write()
对缓冲流进行操作将数据复制到内存缓冲区中,直到缓冲区填满或(通常)直到找到换行符。然后,直到溢出或换行的缓冲区部分被写入write()
底层系统级文件描述符(可以是文件、管道、套接字……)。
我不明白您将如何说服该程序从外部刷新其缓冲区。
值得注意的是,一些程序仅在它们认为不会发送给“真实用户”(即 tty)时才缓冲它们的输出。当他们检测到他们的输出正在被另一个程序读取时,他们会缓冲。
tty 的仿真是Expect在自动化其他流程时所做的事情之一。
Expect有一个纯 Python 实现,但我不知道它处理 tty 仿真的效果如何。
这个问题有点老了,但我认为现在可以通过使用subprocess使用您要执行的命令调用stdbuf来解决您的问题。
尝试使用 -u 参数运行 Python 解释器:
python -u myscript.py
这会强制 Python 使用无缓冲的标准输入/标准输出,这可能会对您有所帮助。