如何通过 python 子进程与 mac 上的应用程序交互?
Posted
技术标签:
【中文标题】如何通过 python 子进程与 mac 上的应用程序交互?【英文标题】:How can I interact with an application on mac through python subprocess? 【发布时间】:2013-02-07 06:32:03 【问题描述】:我知道已经发布了类似的问题,但我见过的方法似乎都不起作用。我想在 mac 上使用 python 子进程启动应用程序 xfoil,并使用脚本发送 xfoil 一堆命令(xfoil 是一个在终端窗口中运行的应用程序,您可以通过文本命令与之交互)。我可以使用脚本启动 xfoil,但我似乎不知道如何向它发送命令。这是我目前正在尝试的代码:
import subprocess as sp
xfoil = sp.Popen(['open', '-a', '/Applications/Xfoil.app/Contents/MacOS/Xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
stdout_data = xfoil.communicate(input='NACA 0012')
我也试过了
xfoil.stdin.write('NACA 0012\n')
为了向 xfoil 发送命令。
【问题讨论】:
你试过subprocess.call()
吗?
Google 表示 xfoil subprocess
using-xfoil-and-automating-via-python-subprocess-module 的热门歌曲
@sotapme:这对 OP 并没有真正的帮助,因为它假设他已经知道如何Popen
xfoil 可执行文件(这样做的示例是针对 Windows),这正是他不知道该怎么做。
我明白了 - 存在/Applications/Xfoil.app/Contents/Resources/xfoil
我猜这是潜在的智慧,但我认为 Xfoil 的全部意义在于 gui。发送该输入确实会得到来自 xfoil
的响应,但与从 cli 驱动它一样多。
@sotapme 是的,我已经看到了你所说的链接(我确实先尝试了谷歌:)但我无法让它工作。
【参考方案1】:
正如man page 所说,
open 命令打开文件(或目录或 URL),就像您双击文件的图标一样。
最终,应用程序由 LaunchServices 启动,但这并不重要——重要的是它不是您的 shell 或 Python 脚本的子项。
另外,open
的全部意义在于打开应用程序本身,因此您不必深入研究它并找到 Unix 可执行文件。如果您已经拥有它,并且想将其作为 Unix 可执行文件运行……只需运行它:
xfoil = sp.Popen(['/Applications/Xfoil.app/Contents/MacOS/Xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
事实证明,在这种情况下,MacOS/Xfoil
甚至不是正确的程序;它显然是Resources/xfoil
周围的某种包装,实际上相当于你在Linux 上得到的/usr/local/bin/xfoil
。所以你想这样做:
xfoil = sp.Popen(['/Applications/Xfoil.app/Contents/Resouces/xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
(另外,从技术上讲,你的命令行根本不应该工作;-a
指定一个应用程序,而不是 Unix 可执行文件,你应该传递至少一个文件来打开。但是因为 LaunchServices 可以像应用程序一样启动 Unix 可执行文件,open
不会检查参数是否有效,open -a /Applications/Xfoil.app/Contents/MacOS/Xfoil
最终会有效地做与open /Applications/Xfoil.app/Contents/MacOS/Xfoil
相同的事情。)
为了未来读者的利益,我将包含来自 cmets 的这些信息:
如果您只是向stdin
写一行然后从函数返回/从主脚本的末尾/等等,Popen
对象将被垃圾收集,关闭它的两个管道。如果xfoil
还没有完成运行,它会在下次尝试写入任何输出时出现错误,显然它通过打印Fortran runtime error: end of file
(到stderr?)和保释来处理这个问题。您需要致电xfoil.wait()
(或其他隐含的wait
s)来防止这种情况发生。
【讨论】:
啊,这给了我一些解释,但它仍然不起作用:Scommunicate() 和 stdin.write() 没有做任何事情。该应用程序也使用您的方法启动,但仅此而已。我是否以错误的方式向它发送命令? :SXfoil
内部的可执行文件 Xfoil.app
实际上并不意味着可以从命令行运行。尝试从终端中的 bash shell 运行它,看看是否可以与之交互。如果这不起作用,subprocess
将不起作用。您要么需要使用其他一些机制来控制它,要么需要获得一个以不同方式构建的 xfoil 副本。
或者……给定 sotapme 的一个 cmets,可能您已经确实有一个可用的可执行文件,但它是 /Applications/Xfoil.app/Contents/Resources/xfoil
,而 /Applications/Xfoil.app/Contents/MacOS/Xfoil
是它的包装器,这只是运行前者而不是后者的问题。再一次,从 Terminal.app 试试看。
我可以与之交互,但它在单独的终端窗口中出现。这有什么关系吗?它是否应该出现在同一个终端窗口中才能正常工作?
你试过Resources/xfoil
吗?正如我在上一条评论中解释的那样,MacOS/Xfoil
可能是一个包装器,例如,启动一个新的终端窗口,然后在其中运行 Resources/xfoil
。 (这只是一个例子——包装器可以代替,例如,将Resources/xfoil
作为子进程触发,并将其输入和输出显式连接到终端窗口。)以上是关于如何通过 python 子进程与 mac 上的应用程序交互?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Mac 上的 python 脚本中删除 bash 历史记录?
如何使用 python 通过子进程与 Excel 文件进行通信? [关闭]
在 Windows 上的 Python Popen 子进程中暂停 FFmpeg 编码