通过Python与Windows控制台应用程序交互

时间:2009-07-14 11:46:04

标签: 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 个答案:

答案 0 :(得分:7)

您的问题是您正在尝试控制交互式应用程序。

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()

答案 1 :(得分:2)

您是否尝试强制使用Windows端线? 即。

p.stdin.write( 'command1 \r\n' )
p.stdout.readline()

更新:

我刚检查了windows cmd.exe上的解决方案,它与readline()一起使用。但它有一个问题Popen的stdout.readline 阻止。因此,如果应用程序将返回没有结束的内容,您的应用程序将永远停留。

但是有一个解决方法:http://code.activestate.com/recipes/440554/

答案 2 :(得分:0)

我想你可能想尝试使用readline()?

编辑:对不起,误会了。

也许this问题对您有帮助吗?

答案 3 :(得分:0)

控制台应用程序是否可能以某种方式缓冲其输出,以便在管道关闭时仅将其发送到stdout?如果您可以访问控制台应用程序的代码,可能在一批输出数据可能有用之后粘贴刷新?

或者,它实际上是出于某种原因写入stderr而不是stdout吗?

再次查看你的代码并想到别的东西,我看到你正在发送“命令\ n”。控制台应用程序可以简单地等待回车字符而不是新行吗?也许控制台应用程序在产生任何输出之前等待您提交命令。

答案 4 :(得分:0)

这里有完全相同的问题。我挖掘了DrPython源代码并窃取了 wx.Execute()解决方案,该工作正常,特别是如果您的脚本已经在使用wx。我从未在Windows平台上找到正确的解决方案......