Put another way, is there a cross-platform way of knowing which file will be executed by subprocess.Popen(file) without first executing it?
- 16,328
 - 12
 - 61
 - 75
 
- 
                    2https://github.com/amoffat/pbs/blob/master/pbs.py#L95 – Josh Lee Mar 26 '12 at 18:21
 - 
                    By default, subprocess inherents the environment of the parent process. So for any executable in the PATH (or the OS in question's equivalent) you don't need to specifiy the location. – Roland Smith Mar 26 '12 at 20:12
 - 
                    @JoshLee looks like PBS is no longer available. – Joe Jun 03 '13 at 19:16
 - 
                    1https://github.com/amoffat/sh/blob/master/sh.py#L162 – Josh Lee Jun 03 '13 at 19:40
 
3 Answers
Python 3.3 added shutil.which() to provide a cross-platform means of discovering executables:
http://docs.python.org/3.3/library/shutil.html#shutil.which
Return the path to an executable which would be run if the given cmd was called. If no cmd would be called, return None.
Sample calls:
>>> shutil.which("python")
'/usr/local/bin/python'
>>> shutil.which("python")
'C:\\Python33\\python.EXE'
Unfortunately, this has not been backported to 2.7.x.
- 19,579
 - 7
 - 67
 - 84
 
- 
                    4Python source for version 3.3's implementation of shutil.which is here (only a few dozen lines): http://hg.python.org/cpython/file/6860263c05b3/Lib/shutil.py#l1068 – joemaller Jun 10 '13 at 13:53
 - 
                    2if you change line 1110 to `if any([cmd.lower().endswith(ext.lower()) for ext in pathext])` (turn the generator to a list) than it will work in python 2.7. – Chris Hagmann Apr 11 '14 at 13:01
 - 
                    3
 - 
                    
 - 
                    3
 
An option for Python 2 and 3:
from distutils.spawn import find_executable
find_executable('python')  # '/usr/bin/python'
find_executable('does_not_exist')  # None
find_executable(executable, path=None) simply tries to find 'executable' in the directories listed in 'path'.  Defaults to os.environ['PATH'] if 'path' is None.  Returns the complete path to 'executable' or None if not found.
Keep in mind that unlike which, find_executable does not actually check that the result is marked as executable. You may want to call os.access(path, os.X_OK) to check that on your own if you want to be certain that subprocess.Popen will be able to execute the file.
Also of note, shutil.which of Python 3.3+ has been backported and made available for Python 2.6, 2.7, and 3.x via the 3rd-party module whichcraft.
It is available for installation via the aforementioned GitHub page (i.e. pip install git+https://github.com/pydanny/whichcraft.git) or the Python package index (i.e. pip install whichcraft). It can be used like such:
from whichcraft import which
which('wget')  # '/usr/bin/wget'
- 5,122
 - 3
 - 29
 - 38
 
- 
                    1Avoid distutils because it used deprecated imp which creates a runtime warning. – sorin May 03 '20 at 10:15
 
outdated (not longer true)
I believe there is none in the python libraries
>>> def which(pgm):
    path=os.getenv('PATH')
    for p in path.split(os.path.pathsep):
        p=os.path.join(p,pgm)
        if os.path.exists(p) and os.access(p,os.X_OK):
            return p
        
>>> os.which=which
>>> os.which('ls.exe')
'C:\\GNUwin32\\bin\\ls.exe'