testingPython中是否存在可执行文件?

在Python中,是否有可移植的简单方法来testing一个可执行程序是否存在?

简单地说,我的意思是像which命令,这将是完美的。 我不想手动searchPATH,也不想用Popen &al试图执行它,看看它是否失败(这就是我现在正在做的,但想象它是launchmissiles

我能想到的最简单的方法是:

 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 

编辑 :更新的代码示例,以包括处理情况下的逻辑提供的参数已经是可执行文件的完整path,即“which / bin / ls”。 这模仿了UNIX'which'命令的行为。

编辑 :更新使用os.path.isfile()而不是os.path.exists()每个注释。

编辑path.strip('"')似乎是在这里做的错误的事情。无论是Windows或POSIX似乎鼓励引用PATH项目。

我知道这是一个古老的问题,但是你可以使用distutils.spawn.find_executable 。 这已经被logging在python 2.4之后 ,并且从python 1.6开始就已经存在了。 另外,Python 3.3现在提供了shutil.which()

Python 3.3现在提供了shutil.which() 。

对于Python 3.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)) 

这是杰伊的答案的单行,在这里作为一个lambda函数:

 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') 

或者最后,作为一个函数缩进:

 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和更高版本:

 import shutil command = 'ls' shutil.which(command) is not None 

作为Jan-Philip Gehrcke的单线答案 :

 cmd_exists = lambda x: shutil.which(x) is not None 

作为一个def:

 def cmd_exists(cmd): return shutil.which(cmd) is not None 

只要记得在Windows上指定文件扩展名。 否则,你必须使用PATHEXT环境variables为窗口写一个非常复杂的is_exe 。 您可能只想使用FindPath 。

OTOH,你为什么还要打扰search可执行文件? 操作系统将作为popen调用的一部分为您执行,如果没有find可执行文件,将引发exception。 所有你需要做的是为给定的操作系统捕捉正确的exception。 请注意,在Windows上,如果未findexe ,则subprocess.Popen(exe, shell=True)将自动失败。


PATHEXT纳入上面的实现(在Jay的回答中):

 def which(program): def is_exe(fpath): return os.path.exists(fpath) and os.access(fpath, os.X_OK) 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)

这似乎是为我工作:

编辑在Linux上工作,感谢Mestreion

 def cmd_exists(cmd): return subprocess.call("type " + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 

我们在这里做的是使用内置命令type并检查退出代码。 如果没有这样的命令, type将以1(或者非零状态码)退出。

关于stdout和stderr的一点是为了使type命令的输出保持沉默,因为我们只对退出状态代码感兴趣。

用法示例:

 >>> cmd_exists("jsmin") True >>> cmd_exists("cssmin") False >>> cmd_exists("ls") True >>> cmd_exists("dir") False >>> cmd_exists("node") True >>> cmd_exists("steam") False 

有关path名的一些有用的function,请参阅os.path模块。 要检查现有文件是否可执行,请使用os.access(path,mode)和os.X_OK模式。

os.X_OK

要包含在access()模式参数中的值,以确定是否可以执行path。

编辑:build议which()实现缺less一个线索 – 使用os.path.join()来build立完整的文件名。

基于更容易请求宽恕而不是权限,我只是尝试使用它并捕获错误(在这种情况下,OSError – 我检查文件不存在,文件不可执行,它们都给OSError)。

如果可执行文件具有类似于--version标志的快速--version ,则会有所帮助。

 import subprocess myexec = "python2.8" try: subprocess.call([myexec, '--version'] except OSError: print "%s not found on path" % myexec 

这不是一个通用的解决scheme,但是对于很多用例(代码需要查找一个众所周知的可执行文件的用例)来说,这将是最简单的方法。

最好的例子应该是Python 3中的python bulit-in模块shutil.which()。链接是https://hg.python.org/cpython/file/default/Lib/shutil.py

我在StackOverflow中发现了一些解决了我的问题。 这个工作提供的可执行文件有一个选项(如–help或–version)输出的东西,并返回退出状态为零。 请参阅在Python调用可执行文件中抑制输出 – 如果可执行文件位于path中,则此答案中代码段末尾的“结果”将为零,否则最可能为1。

我知道我在这里是一个死灵法师,但是我偶然发现了这个问题,并且所接受的解决scheme对我来说并不适用于所有情况。 特别是“可执行”模式检测,以及提供文件扩展名的要求。 此外,python3.3的shutil.which (使用PATHEXT )和python2.4 +的distutils.spawn.find_executable (只是尝试添加'.exe' )只能在一个案例子集中工作。

所以我写了一个“超级”版本(根据接受的答案,以及Suraj的PATHEXTbuild议)。 这个版本的任务更加彻底,首先尝试了一系列“宽带”宽度优先技术,并最终尝试在PATH空间上进行更细粒度的search:

 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 

用法如下所示:

 >>> which.which("meld") 'C:\\Program Files (x86)\\Meld\\meld\\meld.exe' 

在这种情况下,我接受的解决scheme并不适用于我,因为在目录中也有类似于meld.1meld.icomeld.doap等的文件,其中之一被返回(大概是因为按照字典顺序meld.doap ),因为可执行文件在接受的答案testing是不完整的,并给予误报。

如果你有bash和函数shsubprocess.Popen( ... ).communicate() ),
使用bash内buildtype

 type -p ls => /bin/ls type -p nonesuch => "" 

一个重要的问题是“ 为什么你需要testing可执行程序是否存在? 也许你不? 😉

最近我需要这个function来启动查看器的PNG文件。 我想迭代一些预定义的查看器并运行第一个存在的。 幸运的是,我碰到了os.startfile 。 好多了! 简单,便携,并使用系统上的默认查看器:

 >>> os.startfile('yourfile.png') 

更新:我错了os.startfile是可移植的…它只是Windows。 在Mac上,您必须运行open命令。 和Unix上的xdg_open 。 添加Mac和Unix对os.startfile支持有一个Python问题 。

这似乎很简单,并在python2和3工程

 try: subprocess.check_output('which executable',shell=True) except: sys.exit('ERROR: executable not found') 

增加了窗口支持

 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上,反之亦然。

看起来显而易见的select是“which”,通过popenparsing结果,但是你可以使用os类来模拟。 在伪Python中,它看起来像这样:

 for each element r in path: for each file f in directory p: if f is executable: return True 

所以基本上你想要在挂载的文件系统中find一个文件(不一定只在PATH目录中),并检查它是否可执行。 这转化为以下计划:

  • 枚举本地安装的文件系统中的所有文件
  • 匹配名称模式的结果
  • find每个文件检查它是否可执行

我会说,以便携的方式做这件事需要大量的计算能力和时间。 这真的是你需要的吗?

在标准的Python发行版中有一个which.py脚本(比如在Windows '\PythonXX\Tools\Scripts\which.py' )。

编辑: which.py取决于ls因此它不是跨平台的。

以前的例子都不适用于所有的平台。 通常他们无法在Windows上工作,因为您可以在没有文件扩展名的情况下执行并且您可以注册新的扩展名。 例如,在Windows上,如果安装了python,就足够执行'file.py',它就可以工作。

我唯一有效和便携的解决scheme是执行命令并查看错误代码。 任何体面的可执行文件都应该有一组不会执行任何操作的调用参数。

您可以尝试使用名为“sh”的外部库( http://amoffat.github.io/sh/ )。

 import sh print sh.which('ls') # prints '/bin/ls' depending on your setup print sh.which('xxx') # prints None 

使用python结构库:

 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