Skip to content

Instantly share code, notes, and snippets.

@techtonik
Last active April 4, 2022 06:23
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save techtonik/4368898 to your computer and use it in GitHub Desktop.
Save techtonik/4368898 to your computer and use it in GitHub Desktop.
Python Which/Where - Find executable
#!/usr/bin/env python
# https://gist.github.com/4368898
# Public domain code by anatoly techtonik <techtonik@gmail.com>
# AKA Linux `which` and Windows `where`
# For Python 3 you probably want
# https://docs.python.org/dev/library/shutil.html#shutil.which
import os
import sys
def find_executable(executable, path=None):
"""Find if 'executable' can be run. Looks for it in 'path'
(string that lists directories separated by 'os.pathsep';
defaults to os.environ['PATH']). Checks for all executable
extensions. Returns full path or None if no command is found.
"""
if path is None:
path = os.environ['PATH']
paths = path.split(os.pathsep)
extlist = ['']
if os.name == 'os2':
(base, ext) = os.path.splitext(executable)
# executable files on OS/2 can have an arbitrary extension, but
# .exe is automatically appended if no dot is present in the name
if not ext:
executable = executable + ".exe"
elif sys.platform == 'win32':
pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
(base, ext) = os.path.splitext(executable)
if ext.lower() not in pathext:
extlist = pathext
# Windows looks for binaries in current dir first
paths.insert(0, '')
for ext in extlist:
execname = executable + ext
for p in paths:
f = os.path.join(p, execname)
if os.path.isfile(f):
return f
else:
return None
if __name__ == '__main__':
if sys.argv[1:]:
print(find_executable(sys.argv[1]))
else:
print('usage: find_executable.py <progname>')
@phdru
Copy link

phdru commented Apr 29, 2017

Hi! Can I suggest a patch?

0a1,2
> #!/usr/bin/env python
> 
41c43,44
< # print find_executable('hg')
---
> if __name__ == '__main__':
>     print(find_executable('git'))

@KeithHanlan
Copy link

You should not automatically check for executable in the current working directory. This makes it too easy for the user to accidentally execute a trojan. Users who really really trust their environment can explicitly add "." to their search PATH if they wish but it is a bad idea.

In short, remove "if os.path.isfile(execname)" and use only the contents of the else block.

@rth
Copy link

rth commented Feb 7, 2018

As of Python 3.3 there is also shutil.which.

@stuaxo
Copy link

stuaxo commented Feb 20, 2019

For python 2 there is from distutils.spawn.find_executable, the only weirdness is that on windows it will capitalize the extension.

@sergio44kk
Copy link

is there any way to make it look in deeper paths? so it would check the whole C DRIVE?

@techtonik
Copy link
Author

@phdru thanks for the suggestion. Added shebang and command line argument for easy testing with different names.

@techtonik
Copy link
Author

@KeithHanlan good catch. I was probably writing it from Windows, where it was the default system behavior. There is no point to port this insecurity to Linux.

@techtonik
Copy link
Author

techtonik commented Jan 3, 2021

@KeithHanlan the security issue is now fixed. The old behavior is preserved only for Windows.

@techtonik
Copy link
Author

@sergio44k you need a standard code for recursive directory search. https://stackoverflow.com/questions/2186525/how-to-use-glob-to-find-files-recursively should help.

@sergeyklay
Copy link

sergeyklay commented Jun 17, 2021

@rth
As of Python 3.3 there is also shutil.which.

The most valuable comment for me. The entire solution is just to call shutil.which.

@techtonik
Copy link
Author

Added a link to shutil.which for Python 3 users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment