j sad
j sad

Reputation: 1095

Command works in shell but not in subprocess

I'm trying to run a command using the python subprocess package. I've added the path to the compiled executable to my PATH on an Ubuntu machine.

When I do this, it works:

myexecutable input_file output_file

When I do this, it works:

import subprocess
import shlex

cmd = '/path/to/my/myexecutable input_file output_file'
subprocess.Popen(shlex.split(cmd))

Here's the kicker. When I do this, it doesn't work:

import subprocess
import shlex

cmd = 'myexecutable input_file output_file'
subprocess.Popen(shlex.split(cmd))

It gives me:

OSError                                   Traceback (most recent call last)
<ipython-input-4-8f5c3da8b0a3> in <module>()
----> 1 subprocess.call(shlex.split(cmd))

/home/me/miniconda3/envs/mypy2/lib/python2.7/subprocess.pyc in call(*popenargs, **kwargs)
    170     retcode = call(["ls", "-l"])
    171     """
--> 172     return Popen(*popenargs, **kwargs).wait()
    173
    174

/home/me/miniconda3/envs/mypy2/lib/python2.7/subprocess.pyc in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)
    392                                 p2cread, p2cwrite,
    393                                 c2pread, c2pwrite,
--> 394                                 errread, errwrite)
    395         except Exception:
    396             # Preserve original exception in case os.close raises.

/home/me/miniconda3/envs/mypy2/lib/python2.7/subprocess.pyc in _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, to_close, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite)
   1045                         raise
   1046                 child_exception = pickle.loads(data)
-> 1047                 raise child_exception
   1048
   1049

OSError: [Errno 2] No such file or directory

What gives?

Upvotes: 2

Views: 1896

Answers (1)

AKX
AKX

Reputation: 168824

Whatever shell you're using (as well as subprocess.Popen(..., shell=True), but that comes with caveats) figures out the actual executable based on the PATH environment variable.

subprocess.Popen() by itself does not. One popular way to work around this (i.e. to do that path lookup) on UNIX systems is using the widely available /usr/bin/env tool which does the same expansion, i.e.

subprocess.Popen(['/usr/bin/env', 'mytool', 'hurr', 'durr'])

but that's not portable for Windows.

The best way to go about things is to do the lookup by yourself, that is to figure out the full path of your executable file and pass it to subprocess.Popen()os.path.realpath() might be your friend here.

Upvotes: 1

Related Questions