我有一个bash脚本,它使用read提示符与用户交互,例如:
#!/bin/bash
echo start
read -p "Press something to continue " -n 1 -r
echo got $REPLY.
read -p " Press again " -n 1 -r
echo " done"
我想使用python将脚本作为子进程运行,同时捕获输出并将其以真实的方式显示给用户。浏览这里的各种线程,我提出了这个解决方案,对我来说确实有效,但是非常慢,如果脚本产生大量输出(比手动运行脚本长得多),可能是由于每个字符都连续使用flush:
import subprocess
with subprocess.Popen(['./a.sh'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) as proc:
output_text = ''
while c := proc.stdout.read(1):
print(c, end='', flush=True)
output_text += c
“read(1)”是需要的,因为read是阻塞的,尝试读取较大的块意味着在用户输入之前提示消息不会完全显示。刷新也是必要的,因为如果没有刷新,则输入提示消息仅在要求用户输入输入之后才被打印。
我正在寻找一种解决方案,它将允许阅读大块数据(从而减少打印调用的数量),同时仍然确保在等待用户输入之前向用户显示完整的提示。
此外,对于这个问题,bash脚本是作为输入提供的,不能更改,我们也没有关于其结构的任何信息。我正在尝试编写代码,在呈现和捕获它们的输出的同时一般地执行这些脚本。
与使用较大的块类似,readline在这里不起作用,因为它期望EOL,但是只有在用户输入提示符的输入之后才接收EOL。
我试过查看pexpect,但我看到的所有示例都假定它们知道要查找哪个提示符,而在本例中,我假定它们不知道正在运行的脚本。
在我见过的各种类似问题中,解决方案要么使用单个字符读取(例如,通过调用read(1)或将缓冲区大小设置为1),要么使用readline -这似乎不适合我当前的用例。示例:How to get realtime Python subprocess output?Getting realtime output using subprocessGetting realtime and full output using subprocess
1条答案
按热度按时间bmvo0sr51#
你可以用
from os import read
和read(proc.stdout.fileno(), 4096)
来代替proc.stdout.read(1)
-如果小于给定的长度是可读的,这也会返回。