Ваша проблема в том, что вы пытаетесь управлять интерактивным приложением.
stdout.read()
продолжит чтение, пока не достигнет конца потока, файла или канала. К сожалению, в случае интерактивной программы канал закрывается только тогда, когда программа завершается; что никогда, если отправленная вами команда была чем-то отличным от "quit"
.
Вам нужно будет вернуться к чтению вывода подпроцесса построчно, используя stdout.readline()
, и вам лучше будет узнать, когда программа готова принять команду, а когда выданная программа завершена и вы можете поставить новую. В случае такой программы, как cmd.exe
, даже readline()
будет недостаточно, поскольку строка, указывающая, что может быть отправлена новая команда, не завершается новой строкой, поэтому придется анализировать вывод побайтно. Вот пример сценария, который запускает cmd.exe
, ищет приглашение, затем выдает dir
, а затем exit
:
from subprocess import *
import re
class InteractiveCommand:
def __init__(self, process, prompt):
self.process = process
self.prompt = prompt
self.output = ""
self.wait_for_prompt()
def wait_for_prompt(self):
while not self.prompt.search(self.output):
c = self.process.stdout.read(1)
if c == "":
break
self.output += c
# Now we're at a prompt; clear the output buffer and return its contents
tmp = self.output
self.output = ""
return tmp
def command(self, command):
self.process.stdin.write(command + "\n")
return self.wait_for_prompt()
p = Popen( ["cmd.exe"], stdin=PIPE, stdout=PIPE )
prompt = re.compile(r"^C:\\.*>", re.M)
cmd = InteractiveCommand(p, prompt)
listing = cmd.command("dir")
cmd.command("exit")
print listing
Если время не имеет значения, и интерактивность для пользователя не требуется, просто упростить группировку вызовов можно гораздо проще:
from subprocess import *
p = Popen( ["cmd.exe"], stdin=PIPE, stdout=PIPE )
p.stdin.write("dir\n")
p.stdin.write("exit\n")
print p.stdout.read()