如何通过 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()(或其他隐含的waits)来防止这种情况发生。

【讨论】:

啊,这给了我一些解释,但它仍然不起作用:Scommunicate() 和 stdin.write() 没有做任何事情。该应用程序也使用您的方法启动,但仅此而已。我是否以错误的方式向它发送命令? :S Xfoil 内部的可执行文件 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 编码

无法在 Mac 上创建带有子进程的新控制台

使用Python子进程中的Vim编辑临时文件在Mac OS上无法正常工作

通过 Python 子进程运行时使用仪器获取 iDevices 卡住了