使用 asyncio 将 bash 作为 Python 的子进程运行,但 bash 提示被延迟
Posted
技术标签:
【中文标题】使用 asyncio 将 bash 作为 Python 的子进程运行,但 bash 提示被延迟【英文标题】:Running bash as a subprocess to Python using asyncio, but bash prompts are delayed 【发布时间】:2020-06-08 11:00:31 【问题描述】:我希望从 Python 的 asyncio 控制一个长时间运行的交互式 Bash 子进程,一次向它发送一个命令,然后从它接收结果。
下面的代码片段在 Python 3.7.0、Darwin Kernel 版本 16.7.0 中运行良好,除了 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()
会产生更多代码,但结果相同。
看到stderr
中出现bash: no job control in this shell
消息我有点惊讶,因为我正在运行bash -i
并且因为设置了$PS1
,我想知道这是否与问题有关,但是无法更进一步。
【问题讨论】:
【参考方案1】:这让我耽搁了半天,但在我写完问题后,我花了十分钟才想出一个解决方法。
如果我修改提示使其以\n
结尾,那么proc.stderr
实际上已被刷新,并且一切都运行得非常完美。
【讨论】:
以上是关于使用 asyncio 将 bash 作为 Python 的子进程运行,但 bash 提示被延迟的主要内容,如果未能解决你的问题,请参考以下文章