Python运行守护进程子进程并读取stdout
我需要运行一个程序,并收集它输出到标准输出(stdout)上的内容。这个程序叫做 socat,它需要在我的 Python 脚本运行期间一直在后台运行。socat 一旦启动就会进入守护进程模式,但在此之前,它会输出一些我需要的内容到标准输出,这些内容对我后面的脚本很重要。
命令是: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),但脚本还是一直卡着,无论有没有加 &,即使读取标准错误也是如此。
3 个回答
如果你给它提供了一个用于标准输出(stdout)和错误输出(stderr)的管道,我觉得这个子进程会因为在等着读取这些管道而被阻塞。调用.read()应该会一直读取到文件结束符(EOF),我想这两个问题可能会导致死锁。
不过,我觉得因为.read()会一直读取到文件结束符,所以即使没有错误输出的管道,它也会被阻塞。
我觉得你应该把读取的操作放到一个线程里去做。
这个子进程可能从来不会关闭标准输出(stdout),所以调用 read()
的时候就会一直等待下去。更糟糕的是,当它发现自己是在一个管道中而不是在控制台时,可能会把输出进行缓冲(标准C库会自动这样做,所以这并不是说这个应用写得多聪明)。如果真是这样,可能唯一的解决办法就是使用像 Pexpect 这样的库。
#!/usr/bin/python
from subprocess import Popen, PIPE
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),并将其传递给子进程的标准输出和标准错误来解决这个问题。我们使用fdopen将这个文件描述符转换成一个普通的Python对象,这样就可以去掉缓存。
我不知道你在用socat做什么,但我在想是否可以用pty模块来替代它。你是把一个pty复制到另一个,而openpty会创建一对pty。也许你可以直接使用这些pty?