【问题标题】:How to use Python subprocess to write multiple inputs into custom exe program如何使用 Python 子进程将多个输入写入自定义 exe 程序
【发布时间】:2017-03-15 01:14:03
【问题描述】:

我正在尝试打开可打开 HEC .dss 数据库文件的可执行文件。但是,我似乎只能在打开 exe 后让它读取一个参数,然后它不会读取任何其他内容。有什么办法可以强制它继续插入命令。

此 exe 具有一些独特的功能,其中包括第一个命令询问您要读取的 DSS 文件。然后,您可以输入一个命令来创建输出 txt 文件,它将为其余命令写入该文件。到目前为止,我能够做的是启动程序并在 exe 中运行一个命令(mydss 变量)。但是,在读取第一个命令后,命令提示符中不会使用任何其他命令。我觉得我在这里遗漏了一些东西。代码如下:

##Testing on how to run and use the DSSUTL program
import subprocess
from subprocess import PIPE, STDOUT

DSSUTL = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\DSSUTL.exe"
mydss = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\\forecast.dss"
firstLine = "WR.T TO=PythonTextOutput.txt"
commandLine = "WR.T B=SHAVER RESERVOIR-POOL C=FLOW-IN E=1HOUR F=10203040"
myList = [firstLine, commandLine]
ps = subprocess.Popen([DSSUTL, mydss, myList[1], myList[0]], shell=True)

我也尝试过包含 stdin=subprocess.PIPE,但这只会导致 exe 打开并且它是空白的(当我使用上面的代码打开它时,我可以阅读它并看到它mydss 变量被正确读取)。当我使用 stdoutsterr 时,程序只会打开和关闭。

我也尝试在 stdin=PIPE 开启时使用代码:

ps.stdin.write(myList[1])
ps.stdin.write(myList[0])
ps.communicate()[0]

但是,它没有读取程序中的任何内容。这个程序像命令提示符一样运行,但是,它不是典型的 cmd,因为它是用来读取 DSS 文件类型并生成一个文本文件,其中包含来自 commandLine 变量中的搜索列表的列表

很高兴知道我可以做些什么来修复代码,以便我可以输入额外的命令。了解如何事件检查命令是否由该 exe 发送或处理的任何帮助。最终,我将在 exe 文件中添加更多命令以打印到文本文件,因此如果有任何方法可以让 python 写入 exe 会有所帮助。

【问题讨论】:

  • 它是一个交互式程序,您想驱动与 python 的交互吗?这在使用pexpect 模块的Linux 系统上是可能的,在Windows 上要困难得多。有some limited support,但我不知道它是否适合你。
  • 交互式程序通常也有脚本接口。如果您的程序这样做,那么您可以向标准输入写入命令以获得您想要的。
  • @tdelaney,通常可以在 C 扩展或通过 ctypes 中使用控制台 API。如果父进程与子进程连接到同一个控制台,则它可以写入控制台的输入缓冲区并从控制台的活动屏幕缓冲区中读取。
  • @eryksun - 是的......但是您必须跟踪缓冲区并轮询它以进行更改,这是一项繁重的工作!即便如此,windows libc 仍认为它是一个管道,如果程序是基于 libc 的,它的行为可能会有问题。
  • @tdelaney,对您的第一个响应是肯定的,尽管您可以创建一个包含 9999 行的新屏幕缓冲区,所有这些都使用 NUL 进行初始化,以便于从屏幕上读取行(在许多情况下)。大多数控制台程序都是面向行的,而不是主动绘制屏幕的 curses 样式程序,因此等待控制台句柄并跟踪光标位置就足够了。当控制台必须滚动缓冲区时,这将是一个沉重的负担。第二条评论对我来说没有意义。 CRT 不会将控制台句柄视为管道。

标签: python windows python-2.7 input subprocess


【解决方案1】:

@tdelaney, @eryksun 感谢您的评论,您对管道和延迟的 cmets 真的很有帮助。我能够通过使用以下代码解决问题:

##Testing on how to run and use the DSSUTL program
import subprocess
from subprocess import PIPE, STDOUT
import time

DSSUTL = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\DSSUTL.exe"
mydss = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\\forecast.dss"
location = "WR.T TO=PythonTextOutput.txt" + " WR.T B=SHAVER RESERVOIR-POOL C=FLOW-IN E=1HOUR F=10203040" + "\n"
filecontent1 = "WR.T B=FLORENCE RESERVOIR-POOL C=FLOW-IN E=1HOUR F=10203040" + "\n"
filecontent2 = "WR.T B=HUNTINGTON LAKE-POOL C=FLOW-IN E=1HOUR F=10203040" + "\n"
filecontentList = [filecontent1, filecontent2]
myList = [DSSUTL, mydss] # commandLine, location
ps = subprocess.Popen(myList , shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
time.sleep(1)
# input into stdin
ps.stdin.write(location)
time.sleep(1)
ps.stdin.write(filecontent1)
time.sleep(1)
ps.stdin.write(filecontent2)
time.sleep(1)
print ps.communicate()[0]
# End Script

通过使用管道与程序对话并延迟时间似乎可以解决问题并允许我与控制台对话。即使控制台显示为空白,通过打印communicate() 命令,它也会输出控制台所做的操作并生成带有所需序列的文本文件。

感谢您将我推向正确的方向!

【讨论】:

  • 这里的相关更改似乎是在每行输入中添加尾随'\n',您可以将其放在每个字符串文字的末尾,例如使用'string\n' 而不是'string' + '\n'sleep() 调用不应该是必需的;你只是在写一个管道。您应该能够连接 3 个字符串并将其作为 input 参数写入 communicate。仅供参考,您不是在与控制台交谈; 3 个标准手柄中的每一个都是一个管道。实际上,您已经将stdoutstderr 制作成了同一个管道,但我不建议在大多数情况下这样做。
猜你喜欢
  • 1970-01-01
  • 2020-07-03
  • 2011-04-13
  • 2012-01-18
  • 2023-01-17
相关资源
最近更新 更多