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

Posted

技术标签:

【中文标题】Python 运行守护程序子进程并读取标准输出【英文标题】:Python Run a daemon sub-process & read stdout 【发布时间】:2011-07-21 16:08:06 【问题描述】:

我需要运行一个程序并将其输出收集到标准输出。这个程序(socat)需要在 python 脚本的持续时间内在后台运行。 Socat 运行后会处于 dameon 模式,但首先它会向标准输出输出一些我在脚本的其余部分需要的行。

命令:socat -d -d PTY: PTY:

输出:

2011/03/23 21:12:35 socat[7476] N PTY is /dev/pts/1
2011/03/23 21:12:35 socat[7476] N PTY is /dev/pts/2
2011/03/23 21:12:35 socat[7476] N starting data transfer loop with FDs [3,3] and [5,5]

...

我基本上想在我的程序开始时运行它并让它一直运行到脚本终止,但我需要将两个 /dev/pts/X 名称读入 python。

谁能告诉我怎么做?

我想出了这个只是挂起,我猜是因为它阻止了子进程终止。

#!/usr/bin/python
from subprocess import Popen, PIPE, STDOUT

cmd = 'socat -d -d PTY: PTY: &'

p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
output = p.stdout.read()

# Process the output 
print(output)

感谢您的帮助

编辑:似乎它可能会写入 stderr,但脚本仍然只是挂起和没有 & 甚至从 stderr 读取。

【问题讨论】:

没有& 是否可以工作? 不 :( 遗憾的是,它只是挂起。 您是否尝试过添加打印语句以验证它在您调用 Popen 后被阻塞,而不是在调用 read() 时被阻塞? socat 会产生很多输出,还是只有几行? 【参考方案1】:
#!/usr/bin/python
from subprocess import Popen, PIPE, STDOUT
import pty
import os

cmd = 'socat -d -d PTY: PTY:'

master, slave = pty.openpty()

p = Popen(cmd, shell=True, stdin=PIPE, stdout=slave, stderr=slave, close_fds=True)
stdout = os.fdopen(master)
print stdout.readline()
print stdout.readline()

您的版本有两个问题。首先,您调用 read 时不带参数,这意味着它将尝试读取所有内容。但是由于 socat 没有终止,它永远不会决定它已经读取了所有内容。通过使用 readline,python 只读取直到找到换行符。根据我对您的问题的理解,这就是您所需要的。

第二个问题是 C 标准库会在管道上缓冲输出。我们通过使用 openpty() 函数创建一个 pty 并将其传递给子进程的 stdout 和 stderr 来解决这个问题。我们使用 fdopen 将该文件描述符变成一个常规的 python 对象,然后我们摆脱了缓冲。

我不知道你在用 socat 做什么,但我想知道它是否可以用 pty 模块代替。您正在将一个 pty 复制到另一个,而 openpty 正在创建一对 pty。也许您可以直接使用它们?

【讨论】:

非常感谢,这很好用。我会考虑用内置的 pty 模块替换 socat。 这是救命稻草!【参考方案2】:

子进程可能永远不会关闭标准输出,因此read() 调用将永远等待。更糟糕的是,当它发现它是管道而不是控制台时,它可能会缓冲其输出(标准 C 库会自动执行此操作,因此这与应用程序编写的巧妙程度无关)。如果是这样,可能唯一的选择是使用诸如Pexpect 之类的expect 样式库。

【讨论】:

【参考方案3】:

如果您为 stdout 和 stderr 提供管道,我认为子进程将阻塞等待管道被读取。我认为 .read() 应该读到 EOF。在他们之间,这两个问题很容易陷入僵局。

但是,我认为由于 .read() 会读取到 EOF,因此即使没有 stderr 管道,它也会阻塞。

我想你想把阅读内容放在一个线程中。

【讨论】:

以上是关于Python 运行守护程序子进程并读取标准输出的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中使用管道和超时执行命令(并读取标准输出)

如何读取子进程标准输出的第一个字节,然后在 Python 中丢弃其余字节?

如何读取子进程标准输出的第一个字节,然后在 Python 中丢弃其余字节?

持久的子进程管道 - 没有读取标准输出

Python子进程将数据定向到标准输入

阻止写入标准输出