subprocess.stdout.readline() / subprocess.stdout.read() 之后没有任何反应

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

从python我试图在cosnolly中控制cmd,这是我的代码:

cmd_process = subprocess.Popen(["cmd"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='cp866')

cmd_process.stdin.write('E:')
cmd_process.stdin.flush()

cmd_process.stdin.write('dir\n')
cmd_process.stdin.flush()

接下来我不知道该怎么办。如果我输入:

print(cmd_process.stdout.read())

什么也没有发生,cmd 中没有任何打印,并且 cmd 控制台卡住了。所以我无法在控制台中输入任何内容,这就像永恒的 while 循环

如果我尝试:

for i in range(10):
    print(cmd_process.stdout.readline())

print('after for loop')

它实际上工作得很好,在这个 for 循环之后,会打印“after for 循环”。但如果我输入:

for i in range(1_000):
    print(cmd_process.stdout.readline())

print('after for loop') # <-- won't print and cmd is stuck

不行,cmd卡住了。

如果我对文档的理解正确的话,原因就是所谓的死锁:

https://docs.python.org/3/library/subprocess.html
当使用

stdout=PIPE
stderr=PIPE
时,这将导致死锁,并且子进程会向管道生成足够的输出,从而阻塞等待操作系统管道缓冲区接受更多数据。使用管道时使用
Popen.communicate()
可以避免这种情况。

据我从 Using module 'subprocess' with timeout 答案和文档中了解到,有 subprocess.call()、subprocess.check_call() 和 subprocess.check_output() highter_api 命令。

另外,关于文档中的 .call() :
请勿将

stdout=PIPE
stderr=PIPE
与此功能一起使用。如果子进程生成足够的输出到管道以填充操作系统管道缓冲区,因为管道未被读取,则子进程将阻塞。

问题:1)为什么.read()没有显示任何内容? 2)如何克服僵局?

python subprocess
1个回答
0
投票

您正在与

cmd
进行交互,但尚未完成(其输出流尚未关闭),因此您的循环正在等待下一行。如果 cmd 关闭(例如,您在
write('exit\n')
之后但在循环之前
dir
,您每次在关闭的流上调用
readline
时都会看到循环返回空行,因此您知道命令已结束。

dir
仍在运行时,没有办法知道
cmd
已完成(除了通过超时进行黑客攻击或扫描预期模式)。

使用您想要的 sinlge 命令运行 cmd 怎么样?这样命令就完成了,流也关闭了,这样你就可以知道你在哪里。

cmd_process = subprocess.Popen(["cmd", "/c dir c:\\Windows"], ...

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