首页 > 解决方案 > 在 python 子进程中检测关闭的非阻塞 stdout/stderr 管道

问题描述

我正在使用 Python 以交互方式运行进程。

p = Popen ("/path/to/my-executable", stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=1)

for f in (p.stdout, p.stderr):
    flags = fcntil.fcntl (f, fcntl.F_GETFL) | os.O_NONBLOCK
    fcntl.ftcntl (f, flags)

for line in sys.stdin:
    p.stdin.write (line.encode ('utf-8'))
    ...

假设我从 stdin 读取命令并将其转发到my-executablevia p,此过程可能会或可能不会向 stdout/stderr 输出任何内容,并且它可能会或可能不会终止。

我想等到my-executable“做某事”后再从标准输入读取另一个命令。

我尝试将此bash作为子进程并"exit"写入line其标准输入,当我从其标准输出和 sterr 读取时,标准输出None和标准错误给出b''但我不希望这是一个进程已完成运行的可靠指示(即我不能合理p.wait(),因为该结果中没有任何内容可以决定性地告诉我该过程不会再提供任何输出)。

我如何正确地让这个 Python 脚本等到

?

标签: pythonsubprocesspipeposix

解决方案


您可以使用selectors它,如下所示:

# one-time setup
import selectors
sel = selectors.DefaultSelector()
sel.register(p.stdout, selectors.EVENT_READ)
sel.register(p.stderr, selectors.EVENT_READ)

# each time you want to wait
sel.select()

不过,我建议您使用无缓冲 I/O,而不是行缓冲 I/O。此外,您可以os.set_blocking(f.fileno(), False)让您的 FD 无阻塞,而不必自找麻烦fcntl


推荐阅读