使用asyncio将bash作为Python的子进程运行,但是bash提示被延迟

问题描述 投票:0回答:1

[我希望从Python的asyncio控制一个长时间运行的交互式Bash子进程,一次发送一个命令,并从中接收结果。

下面的代码片段在Python 3.7.0,Darwin Kernel版本16.7.0和except中都运行良好,Bash提示不会立即出现在stderr上,而是似乎在“排队”,直到有其他内容写入为止到stderr

这是一个问题,因为原始程序需要接收Bash提示才能知道先前的命令已完成。

from asyncio.subprocess import PIPE
import asyncio


async def run():
    proc = await asyncio.create_subprocess_exec(
        '/bin/bash', '-i', stdin=PIPE, stdout=PIPE, stderr=PIPE
    )

    async def read(stream):
        message = 'E' if stream is proc.stderr else 'O'
        while True:
            line = await stream.readline()
            if line:
                print(message, line)
            else:
                break

    async def write():
        for command in (b'echo PS1=$PS1', b'ls sub.py', b'ls DOESNT-EXIST'):
            proc.stdin.write(command + b'\n')
            await proc.stdin.drain()
            await asyncio.sleep(0.01)  # TODO: need instead to wait for prompt

    await asyncio.gather(
        read(proc.stderr),
        read(proc.stdout),
        write(),
    )


asyncio.run(run())

结果:

E b'bash: no job control in this shell\n'
O b'PS1=\\u@\\h:\\w$\n'
O b'sub.py\n'
E b'tom@bantam:/code/test/python$ tom@bantam:/code/test/python$ tom@bantam:/code/test/python$ ls: DOESNT-EXIST: No such file or directory\n'

请注意,这三个提示最后都一起出现,并且只有在故意导致错误的情况下才会出现。当然,期望的行为是使提示在出现时立即出现。

使用proc.stderr.read()而不是proc.stderr.read()会产生更多的代码,但结果相同。

[我有点惊讶地看到bash: no job control in this shell消息出现在stderr中,因为我正在运行bash -i并且因为设置了$PS1,我想知道这是否与问题有关,但是避难所无法做到这一点。

python bash subprocess python-asyncio
1个回答
0
投票

这使我忙了半天,但是当我完成问题的写作后,花了十分钟的时间才找到解决方法。

如果我修改提示,使其以\n结尾,则实际上proc.stderr已刷新,并且一切工作都非常完美。

© www.soinside.com 2019 - 2024. All rights reserved.