问题描述
我知道已经发布了类似的问题,但是我所见的任何方法似乎都不起作用.我想在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.
作为手册页说,
最终,应用程序由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
相同的操作.
为了将来的读者受益,我将在评论中包括以下信息:
如果仅向stdin
写一行,然后从函数返回/掉到主脚本等的末尾,则Popen
对象将被垃圾回收,并关闭其两个管道.如果xfoil
尚未完成运行,则下次尝试写入任何输出时会出现错误,并且显然可以通过打印Fortran runtime error: end of file
(到stderr?)并进行打包来处理此问题.您需要调用 xfoil.wait()
(或其他方法)隐式地wait
s)以防止这种情况发生.
I know there are similar questions posted already, but non of the methods I have seen seems to work. I want to launch the application xfoil, on mac, with python subprocess, and send xfoil a bunch of commands with a script (xfoil is an application that runs in a terminal window and you interact with it through text commands). I am able to launch xfoil with the script, but I can't seem to find out how to send commands to it. This is the code I am currently trying:
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')
I have also tried
xfoil.stdin.write('NACA 0012\n')
in order to send commands to xfoil.
As the man page says,
Ultimately, the application gets started by LaunchServices, but that's not important—what's important is that it's not a child of your shell, or Python script.
Also, the whole point of open
is to open the app itself, so you don't have to dig into it and find the Unix executable file. If you already have that, and want to run it as a Unix executable… just run it:
xfoil = sp.Popen(['/Applications/Xfoil.app/Contents/MacOS/Xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
As it turns out, in this case, MacOS/Xfoil
isn't even the right program; it's apparently some kind of wrapper around Resources/xfoil
, which is the actual equivalent to what you get as /usr/local/bin/xfoil
on linux. So you want to do this:
xfoil = sp.Popen(['/Applications/Xfoil.app/Contents/Resouces/xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
(Also, technically, your command line shouldn't even work at all; the -a
specifies an application, not a Unix executable, and you're supposed to pass at least one file to open. But because LaunchServices can launch Unix executables as if they were applications, and open
doesn't check that the arguments are valid, open -a /Applications/Xfoil.app/Contents/MacOS/Xfoil
ends up doing effectively the same thing as open /Applications/Xfoil.app/Contents/MacOS/Xfoil
.)
For the benefit of future readers, I'll include this information from the comments:
If you just write a line to stdin
and then return from the function/fall off the end of the main script/etc., the Popen
object will get garbage collected, closing both of its pipes. If xfoil
hasn't finished running yet, it will get an error the next time it tries to write any output, and apparently it handles this by printing Fortran runtime error: end of file
(to stderr?) and bailing. You need to call xfoil.wait()
(or something else that implicitly wait
s) to prevent this from happening.
这篇关于如何通过python子进程与Mac上的应用程序进行交互?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!