如何正确循环 subprocess.stdout

How do I properly loop through subprocess.stdout

我正在创建一个需要使用 powershell 会话的程序,我发现了如何使用以下代码建立持久会话。但是,当命令 运行 时,我想遍历 powershell 输出的新行。下面的 for 循环是我发现的唯一方法,但它需要一个 EOF 并且没有得到它所以它只是徘徊并且程序永远不会退出。我怎样才能在 stdout 中获取新行的数量,以便我可以正确地遍历它们?

from subprocess import Popen, PIPE

process = Popen(["powershell"], stdin=PIPE, stdout=PIPE)

def ps(command):
    command = bytes("{}\n".format(command), encoding='utf-8')
    process.stdin.write(command)
    process.stdin.flush()

    process.stdout.readline()
    return process.stdout.readline().decode("utf-8")

ps("echo hello world")

for line in process.stdout:
    print(line.strip().decode("utf-8"))

process.stdin.close()
process.wait()

您需要 Powershell 命令来知道何时退出。通常,解决方案不仅是flush,而且是close 子进程的stdin;当它完成工作并在其输入中发现 EOF 时,它应该自行退出。只需更改:

process.stdin.flush()

至:

process.stdin.close()

这意味着 flush 并且还确保子进程知道输入已完成。如果它本身不起作用,您可以在您实际上 运行ning .

如果您必须 运行单个子进程中的多个命令,并且每个命令必须在下一个之前完全消耗一个被发送,有可怕的启发式解决方案可用,例如一次发送三个命令,其中第二个简单地回显一个哨兵字符串,第三个 explicitly flushes stdout (以确保块缓冲并不意味着你死锁等待哨兵卡在子进程的内部缓冲区中),你的循环可以一旦它看到哨兵就终止。没有 sentinel 就更糟了,因为你基本上不知道命令什么时候完成,只需要使用 select/selectors 模块来轮询进程的 stdout 超时,只要有可用数据就读取行,并且 假设 如果没有新的输入可用且没有预期的超时 window.

,则该过程已完成