13

Python 脚本控制 Linux 上的外部应用程序,通过管道将输入传递到外部应用程序标准输入,并通过管道从外部应用程序标准输出读取输出。

问题是对管道的写入是按块而不是按行缓冲的,因此在控制脚本接收数据输出之前会发生延迟,例如外部应用程序中的 printf。

无法更改外部应用程序以添加显式 fflush(0) 调用。

python标准库的pty模块如何配合subprocess模块​​来实现呢?

4

7 回答 7

6

您可以使用 PTY 通过以下方式解决此问题:

  • 创建 pty 主/从对;
  • 将子进程的stdin、stdout和stderr连接到pty从设备;
  • 读取和写入父级中的 pty master。
于 2009-10-10T11:56:37.147 回答
5

这样做是可能的,但我能想到的唯一解决方案是相当复杂、不可移植,并且可能充满有问题的细节。您可以使用 LD_PRELOAD 使外部应用程序加载动态库,该动态库包含调用 setvbuf 以取消缓冲标准输出的构造函数。您可能还希望在库中包装 setvbuf 以防止应用程序显式缓冲其自己的标准输出。而且您需要包装 fwrite 和 printf 以便它们在每次调用时刷新。编写要预加载的 .so 将使您脱离 python。

于 2009-10-09T15:58:32.303 回答
3

我不认为这是可能的。如果源应用程序不刷新其传出缓冲区,则数据将不会到达该进程之外,直到缓冲区溢出并强制刷新。

请注意,诸如file之类的完善命令如何具有一个选项 (-n),使其显式刷新其输出。在从管道读取输入文件名并打印检测到的类型的模式下使用文件时,这是必需的。由于在此模式下,文件程序在完成后不会退出,否则不会出现输出。

在较低的层次上考虑这一点:输出缓冲仅仅意味着write()对缓冲流进行操作将数据复制到内存缓冲区中,直到缓冲区填满或(通常)直到找到换行符。然后,直到溢出或换行的缓冲区部分被写入write()底层系统级文件描述符(可以是文件、管道、套接字……)。

我不明白您将如何说服该程序从外部刷新其缓冲区。

于 2009-10-09T14:36:23.463 回答
2

值得注意的是,一些程序仅在它们认为不会发送给“真实用户”(即 tty)时才缓冲它们的输出。当他们检测到他们的输出正在被另一个程序读取时,他们会缓冲。

tty 的仿真是Expect在自动化其他流程时所做的事情之一。

Expect有一个纯 Python 实现,但我不知道它处理 tty 仿真的效果如何。

于 2009-10-09T16:02:16.643 回答
2

这个问题的答案可能会有所帮助:

Python 运行守护程序子进程并读取标准输出

似乎正在解决同样的问题。

于 2011-06-07T19:07:53.740 回答
1

这个问题有点老了,但我认为现在可以通过使用subprocess使用您要执行的命令调用stdbuf来解决您的问题。

于 2012-02-28T06:50:45.000 回答
-1

尝试使用 -u 参数运行 Python 解释器:

python -u myscript.py

这会强制 Python 使用无缓冲的标准输入/标准输出,这可能会对您有所帮助。

于 2009-10-09T14:33:28.413 回答