在Python中,是否有一种可移植且简单的方法来测试可执行程序是否存在?
简单来说,我的意思是which
命令,这将是完美的。我不想手动搜索PATH或尝试使用Popen
&并看看它是否失败(这就是我现在正在做的,但想象它是launchmissiles
)
答案 0 :(得分:311)
我能想到的最简单方法:
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()。
修改:path.strip('"')
似乎在这里做错了。 Windows和POSIX似乎都不鼓励引用引用的PATH项目。
答案 1 :(得分:290)
我知道这是一个古老的问题,但您可以使用distutils.spawn.find_executable
。这是documented since python 2.4并且自python 1.6以来就存在。
import distutils.spawn
distutils.spawn.find_executable("notepad.exe")
此外,Python 3.3现在提供shutil.which()
。
答案 2 :(得分:126)
Python 3.3现在提供shutil.which()。
答案 3 :(得分:33)
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's Answer的单行,也是lambda func:
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)
)
import shutil
command = 'ls'
shutil.which(command) is not None
作为Jan-Philip Gehrcke Answer的一句话:
cmd_exists = lambda x: shutil.which(x) is not None
作为def:
def cmd_exists(cmd):
return shutil.which(cmd) is not None
答案 4 :(得分:17)
请记住在Windows上指定文件扩展名。否则,您必须使用is_exe
环境变量为Windows编写一个非常复杂的PATHEXT
。您可能只想使用FindPath。
popen
电话和电话的一部分为您完成。如果找不到可执行文件,将引发异常。您需要做的就是捕获给定操作系统的正确异常。请注意,在Windows上,如果找不到subprocess.Popen(exe, shell=True)
,exe
将无提示失败。
将PATHEXT
合并到which
的上述实现中(在Jay的回答中):
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
答案 5 :(得分:16)
这似乎对我有用:
已编辑在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
答案 6 :(得分:7)
有关路径名的一些有用功能,请参阅os.path模块。要检查现有文件是否可执行,请使用os.access(path, mode)和os.X_OK模式。
os.X_OK
要包含在access()的mode参数中以确定是否可以执行路径的值。
编辑:建议的which()
实施缺少一条线索 - 使用os.path.join()
构建完整的文件名。
答案 7 :(得分:5)
基于它是easier to ask forgiveness than permission我会尝试使用它并捕获错误(在这种情况下的OSError - 我检查文件不存在,文件不可执行,它们都给出了OSError)。
如果可执行文件具有类似--version
标志的快速无操作,则会有所帮助。
import subprocess
myexec = "python2.8"
try:
subprocess.call([myexec, '--version']
except OSError:
print "%s not found on path" % myexec
这不是一般解决方案,但对于许多用例来说是最简单的方法 - 代码需要查找一个众所周知的可执行文件。
答案 8 :(得分:5)
我知道我在这里是一个死灵法师,但我偶然发现了这个问题,并且所接受的解决方案对我来说并不适用于所有情况。无论如何,提交它可能是有用的。特别是,“可执行”模式检测,以及提供文件扩展名的要求。此外,python3.3的shutil.which
(使用PATHEXT
)和python2.4 +的distutils.spawn.find_executable
(只是尝试添加'.exe'
)仅适用于一部分案例。< / p>
所以我写了一个“超级”版本(基于接受的答案,以及来自Suraj的PATHEXT
建议)。此版本的which
更彻底地执行任务,并首先尝试一系列“广义”广度优先技术,并最终在PATH
空间内尝试更细粒度的搜索:
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'
在这种情况下,已接受的解决方案对我不起作用,因为目录中还有meld.1
,meld.ico
,meld.doap
等文件,其中一个已返回(大概是从字典顺序开始)因为在接受的答案中的可执行测试是不完整的并且给出了误报。
答案 9 :(得分:4)
最好的例子应该是Python 3中的python bulit-in模块shutil.which()。链接是https://hg.python.org/cpython/file/default/Lib/shutil.py
答案 10 :(得分:2)
我在StackOverflow中找到了解决问题的方法。这项工作提供了可执行文件有一个选项(如--help或--version)输出的东西,并返回退出状态为零。请参阅Suppress output in Python calls to executables - 如果可执行文件位于路径中,则此答案中代码段末尾的“结果”将为零,否则最有可能为1。
答案 11 :(得分:2)
这看起来很简单,可以在python 2和3中使用
try: subprocess.check_output('which executable',shell=True)
except: sys.exit('ERROR: executable not found')
答案 12 :(得分:1)
一个重要的问题是“为什么你需要测试可执行文件是否存在?”也许你没有? ;-)
最近我需要此功能来启动PNG文件的查看器。我想迭代一些预定义的查看器并运行第一个存在的查看器。幸运的是,我遇到了os.startfile
。它好多了!简单,便携,并使用系统上的默认查看器:
>>> os.startfile('yourfile.png')
更新:我错误地认为os.startfile
是可移植的...它只是Windows。在Mac上,您必须运行open
命令。在Unix上xdg_open
。有os.startfile
为{{1}}添加Mac和Unix支持。
答案 13 :(得分:1)
您可以尝试名为“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
答案 14 :(得分:1)
添加了Windows支持
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
答案 15 :(得分:0)
标准Python发行版中有一个which.py脚本(例如,在Windows '\PythonXX\Tools\Scripts\which.py'
上)。
编辑:which.py
取决于ls
,因此它不是跨平台的。
答案 16 :(得分:0)
以前的示例都不适用于所有平台。通常它们无法在Windows上运行,因为您可以在没有文件扩展名和的情况下执行,您可以注册新的扩展名。例如在Windows上,如果python安装得很好,就足以执行'file.py',它就可以工作了。
我唯一有效且可移植的解决方案是执行命令并查看错误代码。任何体面的可执行文件都应该有一组无效的调用参数。
答案 17 :(得分:0)
您可以判断os模块是否存在文件。考虑到很多东西都可以在nix上执行,而不是在Windows上,反之亦然,特别是可执行文件看起来非常不可移植。
答案 18 :(得分:0)
所以基本上你想在挂载的文件系统中找到一个文件(不一定只在PATH目录中)并检查它是否可执行。这转换为以下计划:
我会说,以便携方式执行此操作需要大量的计算能力和时间。这真的是你需要的吗?
答案 19 :(得分:0)
似乎明显的选择是“which”,通过popen解析结果,但你可以使用os类来模拟它。在伪皮带中,它看起来像这样:
for each element r in path:
for each file f in directory p:
if f is executable:
return True
答案 20 :(得分:-3)
使用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