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

10 投票
5 回答
16511 浏览
提问于 2025-04-15 12:53

我在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

我觉得你可以试试用readline()这个方法?

编辑:抱歉,我理解错了。

也许这个问题能帮到你?

2

你有没有尝试过强制使用Windows的换行符?

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

更新:

我刚刚在Windows的命令提示符下检查了这个解决方案,发现它在使用readline()时是有效的。不过,它有一个问题,就是Popen的stdout.readline会阻塞。也就是说,如果应用程序返回一些没有换行符的内容,你的应用就会一直卡在那里,无法继续。

不过有一个解决办法,可以看看这个链接:http://code.activestate.com/recipes/440554/

8

你遇到的问题是,你想控制一个互动应用程序。

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

撰写回答