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的PATHEXT
build议)。 这个版本的任务更加彻底,首先尝试了一系列“宽带”宽度优先技术,并最终尝试在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.1
, meld.ico
, meld.doap
等的文件,其中之一被返回(大概是因为按照字典顺序meld.doap
),因为可执行文件在接受的答案testing是不完整的,并给予误报。
如果你有bash
和函数sh
( subprocess.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