Simon TheChain Simon TheChain - 1 month ago 7
Python Question

Python 2 subprocess arguments error under Mac

I'm trying to do a Mac version of a program that runs fine under Windows, using python 2.7. Under Mac (OS X El Capitan running in VirtualBox), it fails because the arguments I pass to the shell are not recognized properly.

Original code:

for item in source_files:

# core process
output = sub.Popen(["mhl", "verify", "-vv", "-f", item, ">", text_report],
shell=True,
stdout=sub.PIPE,
stderr=sub.PIPE)
stdout_value, stderr_value = output.communicate()


Under Mac only the 'mhl' argument is recognized so I tried this:

sub.Popen(['mhl verify -vv -f', item, '>', text_report]


Now the command works but the item (a .mhl file) is not recognized so I tried this:

sub.Popen(['mhl verify -vv -f', '/Users/simon/Documents/Documents.mhl', '>', text_report]


and this:

sub.Popen(['mhl verify -vv -f', r'/Users/simon/Documents/Documents.mhl', '>', text_report]


Same results, it tells me a mhl file should follow the '-f' argument. If I add the item directly to the first argument it works fine:

sub.Popen(['mhl verify -vv -f /Users/simon/Documents/Documents.mhl', '>', text_report]


What am I missing here?

Answer

You are asking the OS to run the executable 'mhl verify -vv -f', and there is no such executable. No shell splitting takes place on the spaces there.

With shell=True you'd want to pass in everything as one string, not as separate arguments:

sub.Popen('mhl verify -vv -f {} > {}'.format(item, text_report),
          shell=True, stdout=sub.PIPE, stderr=sub.PIPE)

Note that there is little point in directing stdout to a pipe here, since all stdout output from the mhl command is being redirected to a file.

If you wanted to capture the output of the mhl command directly in Python, I'd not use a shell intermediary here; run without shell=True and then just use subprocess.check_output() to retrieve the output:

output = sub.check_output(['mhl', 'verify', '-vv', '-f', item])

Note that now the program name and the arguments must be passed in ready-split into separate strings.