通过 Python 与 Windows 控制台应用程序交互
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1124884/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Interact with a Windows console application via Python
提问by QAZ
I am using python 2.5 on Windows. I wish to interact with a console process via Popen. I currently have this small snippet of code:
我在 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()
I can write to stdin but can not read from stdout. Have I missed a step? I don't want to use p.communicate( "command" )[0] as it terminates the process and I need to interact with the process dynamically over time.
我可以写入标准输入但无法从标准输出读取。我错过了一步吗?我不想使用 p.communicate( "command" )[0] 因为它终止了进程,我需要随着时间的推移与进程动态交互。
Thanks in advance.
提前致谢。
回答by rix0rrr
Your problem here is that you are trying to control an interactive application.
您的问题是您正在尝试控制交互式应用程序。
stdout.read()
will continue reading until it has reached the end of the stream, file or pipe. Unfortunately, in case of an interactive program, the pipe is only closed then whe program exits; which is never, if the command you sent it was anything other than "quit"
.
stdout.read()
将继续读取,直到到达流、文件或管道的末尾。不幸的是,在交互式程序的情况下,管道仅在程序退出时关闭;如果您发送的命令不是"quit"
.
You will have to revert to reading the output of the subprocess line-by-line using stdout.readline()
, and you'd better have a way to tell when the program is ready to accept a command, and when the command you issued to the program is finished and you can supply a new one. In case of a program like cmd.exe
, even readline()
won't suffice as the line that indicates a new command can be sent is not terminated by a newline, so will have to analyze the output byte-by-byte. Here's a sample script that runs cmd.exe
, looks for the prompt, then issues a dir
and then an exit
:
您将不得不使用 恢复到逐行读取子进程的输出stdout.readline()
,并且您最好有一种方法来判断程序何时准备好接受命令,以及您向程序发出的命令何时完成你可以提供一个新的。对于像 那样的程序cmd.exe
,即使readline()
指示可以发送新命令的行不是由换行符终止的,也是不够的,因此必须逐字节分析输出。这是一个运行的示例脚本cmd.exe
,查找提示,然后发出 adir
和 an 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
If the timing isn't important, and interactivity for a user isn't required, it can be a lot simpler just to batch up the calls:
如果时间不重要,并且不需要用户的交互性,那么仅批量调用可能会简单得多:
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()
回答by Piotr Czapla
Have you tried to force windows end lines? i.e.
您是否尝试过强制窗口结束行?IE
p.stdin.write( 'command1 \r\n' )
p.stdout.readline()
UPDATE:
更新:
I've just checked the solution on windows cmd.exe and it works with readline(). But it has one problem Popen's stdout.readline blocks. So if the app will ever return something without endline your app will stuck forever.
我刚刚检查了 windows cmd.exe 上的解决方案,它适用于 readline()。但它有一个问题 Popen 的 stdout.readline blocks。因此,如果应用程序会在没有结束线的情况下返回某些内容,那么您的应用程序将永远卡住。
But there is a work around for that check out: http://code.activestate.com/recipes/440554/
但是有一个解决方法可以检查:http: //code.activestate.com/recipes/440554/
回答by Robert Massa
回答by Midpoint
Is it possible that the console app is buffering its output in some way so that it is only being sent to stdout when the pipe is closed? If you have access to the code for the console app, maybe sticking a flush after a batch of output data might help?
控制台应用程序是否可能以某种方式缓冲其输出,以便仅在管道关闭时才将其发送到 stdout?如果您可以访问控制台应用程序的代码,也许在一批输出数据后坚持刷新可能会有所帮助?
Alternatively, is it actually writing to stderr and instead of stdout for some reason?
或者,由于某种原因,它实际上是写入 stderr 而不是 stdout 吗?
Just looked at your code again and thought of something else, I see you're sending in "command\n". Could the console app be simply waiting for a carriage return character instead of a new line? Maybe the console app is waiting for you to submit the command before it produces any output.
刚刚再次查看您的代码并想到其他东西,我看到您正在发送“命令\n”。控制台应用程序是否可以简单地等待回车符而不是换行符?也许控制台应用程序在生成任何输出之前正在等待您提交命令。
回答by Wojciech Bederski
Had the exact same problem here. I dug into DrPython source code and stole wx.Execute()solution, which is working fine, especially if your script is already using wx. I never found correct solution on windows platform though...
这里有完全相同的问题。我深入研究了 DrPython 源代码并窃取了wx.Execute()解决方案,该解决方案工作正常,特别是如果您的脚本已经在使用 wx。不过,我从未在 Windows 平台上找到正确的解决方案......