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:As it turns out, in this case,
MacOS/Xfoil
isn't even the right program; it's apparently some kind of wrapper aroundResources/xfoil
, which is the actual equivalent to what you get as/usr/local/bin/xfoil
on linux. So you want to do this:(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, andopen
doesn't check that the arguments are valid,open -a /Applications/Xfoil.app/Contents/MacOS/Xfoil
ends up doing effectively the same thing asopen /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., thePopen
object will get garbage collected, closing both of its pipes. Ifxfoil
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 printingFortran runtime error: end of file
(to stderr?) and bailing. You need to callxfoil.wait()
(or something else that implicitlywait
s) to prevent this from happening.