通过Python与Windows控制台应用交互
我在Windows上使用Python 2.5。我想通过Popen与一个控制台程序进行交互。目前我有这段小代码:
p = Popen( ["console_app.exe"], stdin=PIPE, stdout=PIPE )
# issue command 1...
p.stdin.write( 'command1\n' )
result1 = p.stdout.read() # <---- we never return here
# issue command 2...
p.stdin.write( 'command2\n' )
result2 = p.stdout.read()
我可以向标准输入(stdin)写数据,但无法从标准输出(stdout)读取数据。我是不是漏掉了什么步骤?我不想使用p.communicate("command")[0],因为那样会结束这个进程,而我需要随着时间动态地与这个进程进行交互。
提前谢谢你。
5 个回答
你有没有尝试过强制使用Windows的换行符?
p.stdin.write( 'command1 \r\n' )
p.stdout.readline()
更新:
我刚刚在Windows的命令提示符下检查了这个解决方案,发现它在使用readline()时是有效的。不过,它有一个问题,就是Popen的stdout.readline会阻塞。也就是说,如果应用程序返回一些没有换行符的内容,你的应用就会一直卡在那里,无法继续。
不过有一个解决办法,可以看看这个链接:http://code.activestate.com/recipes/440554/
你遇到的问题是,你想控制一个互动应用程序。
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()