如何从Python pty.fork()子输出中读取不完整的行?

how to read an incomplete line from a Python pty.fork() child output?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python

import pty
import os
import sys

pid, out = pty.fork()

if pid:
    try:
        for line in os.fdopen(out):
            sys.stdout.write(line)
    except IOError:
        pass

else:
    sys.stdout.write("foobar")
    sys.stdout.flush()

没有打印。 如何让它打印出孩子发出的不完整线?


以下是纯粹推测:对输入流进行迭代可能是在将字符读入缓冲区时实现的,直到遇到换行符或文件结束条件为止。 如果孩子死了,一些实现(依赖于平台)会从缓冲区中释放剩余的字符。

也许使用一些更低级别的I / O可以避免这个问题。 当我在我的GNU / Linux系统上运行原始脚本时,我没有得到"foobar"而是IOError。 但是,当我将其更改为

1
2
with os.fdopen(out) as istr:
    sys.stdout.write(istr.read())

它打印"foobar"而不会抛出任何异常。

更新:为了一次读取一个流,我们需要求助于更低级别的I / O. 我发现以下内容对我有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pty
import os
import sys

pid, out = pty.fork()

if pid:
    while True:
        buffsz = 10  # Use a larger number in production code.
        buff = b''
        died = False
        try:
            buff = os.read(out, buffsz)
        except IOError:
            died = True
        sys.stdout.write(buff.decode())
        if len(buff) == 0 or died:
            break
else:
    with sys.stdout:
        # Also try writing a longer string with newlines.
        sys.stdout.write("foobar")

不幸的是,这意味着我们需要手动重新组装缓冲区块并扫描换行符。 这很不方便,但肯定可以做到。