1

I have a script file subprocess-script.py as follows:

import subprocess
import platform

command = []
exe = "path/to/myapp.app"
input = "/path/to/in.ext"
output = "/path/to/out.ext"

command.append('open')
command.append('-a')
command.append(f'"{exe}"')
command.append('--args')
command.append("--input")
command.append(f'"{input}"')
command.append("--output")
command.append(f'"{output}"')
command.append('-report')

print("EXECUTE: ", " ".join(command))

subprocess.run(command, shell=True, check=True, capture_output=True, text=True)

I execute the script using command python3 subprocess-script.py and get the following exception:

user@macbookair ~ % python3 subprocess-script.py
EXECUTE:  open -a "path/to/myapp.app" --args --input "/path/to/in.ext" --output "/path/to/out.ext"
Traceback (most recent call last):
  File "/path/to/subprocess-script.py", line XX, in <module>
    result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.7_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['open', '-a', '"path/to/myapp.app"', '--args', '--input', '"/path/to/in.ext"', '--output', '"/path/to/out.ext"']' returned non-zero exit status 1.
user@macbookair ~ %

But when I take the EXECUTE print statement and try out the statement it works perfectly and generates my output file out.ext:

open -a "path/to/myapp.app" --args --input "/path/to/in.ext" --output "/path/to/out.ext"

I suspect I'm building the command incorrectly? Take note I use quotes for my paths intentionally because sometimes the paths contain folders with spaces and that will of course fail if not enclosed in quotation marks. I also tried the -report flag as mentioned in this thread but I don't see any log files generated. This information is missing in the answer. There is a potential solution in this thread where the command list is transformed to a string using " ".join(command) but I'm not sure if this is a workaround or the proper solution.

On windows I don't have a problem where I build the command like this:

command.append('powershell')
command.append('-Command')
command.append(f'& "{exe}"')
command.append('--args')
command.append("--input")
command.append(f'"{input}"')
command.append("--output")
command.append(f'"{output}"')

What might be the problem in the Mac version of the script?

2 Answers 2

1

You are building different commands on Windows and on macOS. The macOS equivalent of the PowerShell command is

subprocess.run(["bash", "-c", "ls \"File Name.txt\""])

This would require additional quotes around paths/files to protect any whitespace from the shell.

But when you use open, no shell is involved and it tries to execute "path/to/myapp.app" which doesn't exist (path/to/myapp.app does).

So either use the bash approach on macOS (and quote the paths), or use open without quoting the paths.

PS: Most likely you don't need either, you can also just run

subprocess.run(["path/to/myapp.app", "--args", "--input", f'{input}'])
3
  • thank you for your response but unfortunately none of these suggestions worked for me. in case you want to know which app im trying to execute it's the vox-convert.app in this download link Jan 19 at 10:27
  • @HarryMcKenzie Please update the question then, with what you've tried and how it failed.
    – nohillside
    Jan 19 at 10:47
  • hey thank you for your time. i finally figured it out. i had to directly execute the binary inside myapp.app/Contents/MacOS/binary-name and then replace all spaces in the exe path with "\ " then convert the final command to a string using " ".join(command) and do subprocess.run(command_str) Jan 19 at 12:30
0

You should navigate to the Contents/MacOS/ directory within the app bundle and execute the binary directly. This directory typically contains the main executable for the application.

command = []

exe = "/path to app which may have spaces/myapp.app/Contents/MacOS/app-binary"

command.append("--input")
command.append(f'"{input}"')
command.append("--output")
command.append(f'"{output}"')

command_str = " ".join(command)

print("EXECUTE: ", command_str)

# subprocess.run(command) # take note this will not work for an unknown reason, well at least for the vengi-voxconvert binary in https://github.com/vengi-voxel/vengi/releases/download/v0.0.28/vengi-0.0.28-Darwin.dmg
subprocess.run(command_str, shell=True, check=True, capture_output=True, text=True)
3
  • Glad to see it work now. The path problem isn't directly related to the situation you describe in the question though, so it might help to explain you got to the solution here (which doesn't use open while the version in the question does).
    – nohillside
    Jan 19 at 13:22
  • sorry i wasnt clear, i just needed the software to run and generate an output via terminal with or without open and i thought that open was the standard way to run software on mac. Then i did some more research and realized that open is mostly associated with GUI and that directly running the binary inside the Contents/MacOS is the way to go for pure console/terminal applications. Well that's how I understand it currently, I could be wrong. And I found out there was no way for my case to work using open and subprocess Jan 19 at 15:42
  • sorry forgot to give u an upvote gave u +1 :) Jan 19 at 15:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .