Test if executable exists in Python?
在Python中,是否有一种可移植且简单的方法来测试可执行程序是否存在?
简单来说,我的意思是像
我能想到的最简单方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def which(program): import os def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None |
编辑:更新的代码示例包括用于处理案例的逻辑,其中提供的参数已经是可执行文件的完整路径,即"which / bin / ls"。这模仿了UNIX'which'命令的行为。
编辑:更新为每个注释使用os.path.isfile()而不是os.path.exists()。
编辑:
我知道这是一个古老的问题,但你可以使用
1 2 | import distutils.spawn distutils.spawn.find_executable("notepad.exe") |
此外,Python 3.3现在提供
Python 3.3现在提供shutil.which()。
对于python 3.2及更早版本:
1 2 | my_command = 'ls' any(os.access(os.path.join(path, my_command), os.X_OK) for path in os.environ["PATH"].split(os.pathsep)) |
这是Jay的答案,也是一个lambda函数:
1 2 | cmd_exists = lambda x: any(os.access(os.path.join(path, x), os.X_OK) for path in os.environ["PATH"].split(os.pathsep)) cmd_exists('ls') |
或者最后,缩进为一个函数:
1 2 3 4 5 | def cmd_exists(cmd): return any( os.access(os.path.join(path, cmd), os.X_OK) for path in os.environ["PATH"].split(os.pathsep) ) |
对于python 3.3及更高版本:
1 2 3 4 | import shutil command = 'ls' shutil.which(command) is not None |
作为Jan-Philip Gehrcke的单行答案:
1 | cmd_exists = lambda x: shutil.which(x) is not None |
作为def:
1 2 | def cmd_exists(cmd): return shutil.which(cmd) is not None |
只需记住在Windows上指定文件扩展名即可。否则,您必须使用
OTOH,你为什么还要费心去搜索可执行文件呢?操作系统将作为
将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def which(program): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) and os.path.isfile(fpath) def ext_candidates(fpath): yield fpath for ext in os.environ.get("PATHEXT","").split(os.pathsep): yield fpath + ext fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) for candidate in ext_candidates(exe_file): if is_exe(candidate): return candidate return None |
对于* nix平台(Linux和OS X)
这似乎对我有用:
由于Mestreion,我被编辑在Linux上工作
1 2 3 | def cmd_exists(cmd): return subprocess.call("type" + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 |
我们在这里做的是使用内置命令
关于stdout和stderr的一点只是为了使
用法示例:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> cmd_exists("jsmin") True >>> cmd_exists("cssmin") False >>> cmd_exists("ls") True >>> cmd_exists("dir") False >>> cmd_exists("node") True >>> cmd_exists("steam") False |
有关路径名的一些有用功能,请参阅os.path模块。要检查现有文件是否可执行,请使用os.access(path,mode)和os.X_OK模式。
os.X_OK
Value to include in the mode parameter of access() to determine if path can be executed.
编辑:建议的
在请求宽恕比允许更容易的基础上,我会尝试使用它并捕获错误(在这种情况下OSError - 我检查文件不存在,文件不可执行,它们都给出了OSError)。
如果可执行文件具有类似
1 2 3 4 5 6 | import subprocess myexec ="python2.8" try: subprocess.call([myexec, '--version'] except OSError: print"%s not found on path" % myexec |
这不是一般解决方案,但对于许多用例来说是最简单的方法 - 代码需要查找一个众所周知的可执行文件。
我知道我在这里是一个死灵法师,但我偶然发现了这个问题,并且所接受的解决方案对我来说并不适用于所有情况。无论如何,提交它可能是有用的。特别是,"可执行"模式检测,以及提供文件扩展名的要求。此外,python3.3的
所以我写了一个"超级"版本(基于接受的答案,以及来自Suraj的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | import os import sys import stat import tempfile def is_case_sensitive_filesystem(): tmphandle, tmppath = tempfile.mkstemp() is_insensitive = os.path.exists(tmppath.upper()) os.close(tmphandle) os.remove(tmppath) return not is_insensitive _IS_CASE_SENSITIVE_FILESYSTEM = is_case_sensitive_filesystem() def which(program, case_sensitive=_IS_CASE_SENSITIVE_FILESYSTEM): """ Simulates unix `which` command. Returns absolute path if program found""" def is_exe(fpath): """ Return true if fpath is a file we have access to that is executable""" accessmode = os.F_OK | os.X_OK if os.path.exists(fpath) and os.access(fpath, accessmode) and not os.path.isdir(fpath): filemode = os.stat(fpath).st_mode ret = bool(filemode & stat.S_IXUSR or filemode & stat.S_IXGRP or filemode & stat.S_IXOTH) return ret def list_file_exts(directory, search_filename=None, ignore_case=True): """ Return list of (filename, extension) tuples which match the search_filename""" if ignore_case: search_filename = search_filename.lower() for root, dirs, files in os.walk(path): for f in files: filename, extension = os.path.splitext(f) if ignore_case: filename = filename.lower() if not search_filename or filename == search_filename: yield (filename, extension) break fpath, fname = os.path.split(program) # is a path: try direct program path if fpath: if is_exe(program): return program elif"win" in sys.platform: # isnt a path: try fname in current directory on windows if is_exe(fname): return program paths = [path.strip('"') for path in os.environ.get("PATH","").split(os.pathsep)] exe_exts = [ext for ext in os.environ.get("PATHEXT","").split(os.pathsep)] if not case_sensitive: exe_exts = map(str.lower, exe_exts) # try append program path per directory for path in paths: exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file # try with known executable extensions per program path per directory for path in paths: filepath = os.path.join(path, program) for extension in exe_exts: exe_file = filepath+extension if is_exe(exe_file): return exe_file # try search program name with"soft" extension search if len(os.path.splitext(fname)[1]) == 0: for path in paths: file_exts = list_file_exts(path, fname, not case_sensitive) for file_ext in file_exts: filename ="".join(file_ext) exe_file = os.path.join(path, filename) if is_exe(exe_file): return exe_file return None |
用法如下:
1 2 | >>> which.which("meld") 'C:\\Program Files (x86)\\Meld\\meld\\meld.exe' |
在这种情况下,接受的解决方案对我来说不起作用,因为在目录中也有像
最好的例子应该是Python 3中的python bulit-in模块shutil.which()。链接是https://hg.python.org/cpython/file/default/Lib/shutil.py
这看起来很简单,并且在python 2和3中都有效
1 2 | try: subprocess.check_output('which executable',shell=True) except: sys.exit('ERROR: executable not found') |
我在StackOverflow中找到了解决问题的方法。这项工作提供了可执行文件有一个选项(如--help或--version)输出的东西,并返回退出状态为零。请参阅Python可执行文件调用中的抑制输出 - 如果可执行文件位于路径中,则此答案中代码段末尾的"结果"将为零,否则最有可能为1。
一个重要的问题是"为什么需要测试可执行文件是否存在?"也许你没有? ;-)
最近我需要此功能来启动PNG文件的查看器。我想迭代一些预定义的查看器并运行第一个存在的查看器。幸运的是,我遇到了
1 | >>> os.startfile('yourfile.png') |
更新:我错误地认为
您可以尝试名为"sh"的外部库(http://amoffat.github.io/sh/)。
1 2 3 | import sh print sh.which('ls') # prints '/bin/ls' depending on your setup print sh.which('xxx') # prints None |
添加了Windows支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | def which(program): path_ext = [""]; ext_list = None if sys.platform =="win32": ext_list = [ext.lower() for ext in os.environ["PATHEXT"].split(";")] def is_exe(fpath): exe = os.path.isfile(fpath) and os.access(fpath, os.X_OK) # search for executable under windows if not exe: if ext_list: for ext in ext_list: exe_path ="%s%s" % (fpath,ext) if os.path.isfile(exe_path) and os.access(exe_path, os.X_OK): path_ext[0] = ext return True return False return exe fpath, fname = os.path.split(program) if fpath: if is_exe(program): return"%s%s" % (program, path_ext[0]) else: for path in os.environ["PATH"].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path, program) if is_exe(exe_file): return"%s%s" % (exe_file, path_ext[0]) return None |
你可以判断一下os模块是否存在一个文件。考虑到很多东西都可以在nix上执行而不是在windows上,反之亦然,特别是一个可执行文件似乎非常不可移植。
以前的示例都不适用于所有平台。通常它们无法在Windows上运行,因为您可以在没有文件扩展名的情况下执行,并且可以注册新的扩展名。例如在Windows上,如果python安装得很好,它就足以执行'file.py'并且它会起作用。
我唯一有效且可移植的解决方案是执行命令并查看错误代码。任何体面的可执行文件都应该有一组无效的调用参数。
标准Python发行版中有一个which.py?疟荆ɡ纾赪indows
编辑:
所以基本上你想在挂载的文件系统中找到一个文件(不一定只在PATH目录中)并检查它是否可执行。这转换为以下计划:
- 枚举本地安装的文件系统中的所有文件
- 匹配结果与名称模式
- 找到每个文件检查它是否可执行
我会说,以便携方式执行此操作需要大量的计算能力和时间。这真的是你需要的吗?
似乎显而易见的选择是"哪个",通过popen解析结果,但你可以使用os类来模拟它。在pseudopython中,它看起来像这样:
1 2 3 4 | for each element r in path: for each file f in directory p: if f is executable: return True |
使用python结构库:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from fabric.api import * def test_cli_exists(): """ Make sure executable exists on the system path. """ with settings(warn_only=True): which = local('which command', capture=True) if not which: print"command does not exist" assert which |