Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this Python subprocess command only work when shell=True on Windows?

I have a python script that involves multiple subprocess.call commands. I wrote the script on a Mac, and it runs perfectly. I just tried running it on Windows and I am baffled by an error.

The following command to call ImageMagick returns "exit status 4":

file1 = "D:/Temp/OCR_test/sample/images/crops/time_0011.png"
subprocess.call(['convert', file1, '-resize', '200%', file1])

Changing the command to the following works:

subprocess.call(['convert', file1, '-resize', '200%', file1], shell=True)

I'm a little wary of using shell=True because of the warnings in the documentation.
I also need the command to work on both Mac and Windows, and I am confused as to why it wouldn't work on Windows (I checked and the command does work using Windows CMD).

Interestingly, the following line worked earlier in the script (where file, lat_crop1, and croplat are defined variables):

subprocess.call(['ffmpeg', '-loglevel', 'panic', '-i', file, '-vf', lat_crop1, '-n', croplat])  

I read this SO question and tried all the suggestions (shlex, variations of my command, etc...), but I still get the same result.

Anyone have any idea how I could modify that line so it can work without shell=True?

Also, what does "exit status 4" mean? I Googled and read so much documentation but found nothing about it.

EDIT: Based on the information provided in the answer, I changed to the command that was not working to subprocess.call(['mogrify', file1, '-resize', '200%', file1]) and that runs successfully in Python on Windows. Luckily ImageMagick provides mogrify as an alternative to convert.

like image 671
Evan Avatar asked Jan 25 '17 20:01

Evan


1 Answers

I suspect you're calling C:\Windows\System32\convert.exe (NTFS/FAT partition converter) instead of imagemagick.

When shell=True, the path finds the convert.bat or convert.cmd script from imagemagick, but without it, the path can only find the .exe file, which is a completely different program, and you get error 4: invalid parameter.

In that particular case, it doesn't work even with an executable, because the "wrong" convert is located in a system path. shell=False only searches in system paths (python subprocess Popen environment PATH?). So that's bad luck that a program named convert is located in the system path.

Try to explicitly add .bat extension like this:

subprocess.call(['convert.bat', file1, '-resize', '200%', file1])

To know which executables are likely to be run you can type:

where convert

in a command prompt.

In your case (an executable), that could be workarounded by passing the absolute path of the executable you want to run.

Another way would be to copy/rename ImageMagick convert to imconvert. Which program calls itself convert and doesn't expect conflicts anyway ?

Or in that case, it's legitimate to leave shell=True, with a nice comment explaining that Microsoft left a confusing (and seldom used convert program in a system path for us to trip into)

Solutions are not pretty, at least there are some.

like image 102
Jean-François Fabre Avatar answered Sep 18 '22 14:09

Jean-François Fabre