在Python中,是否有一种可移植且简单的方法来测试可执行程序是否存在?

我说的简单是指像which命令这样完美的命令。我不想手动搜索PATH或涉及尝试与Popen & al执行它,看看它是否失败(这就是我现在做的,但想象它是launchmissiles)


当前回答

基于请求原谅比请求许可更容易(而且,重要的是,该命令可以安全运行),我会尝试使用它并捕获错误(在本例中是OSError -我检查了文件不存在和文件不可执行,它们都给出了OSError)。

如果可执行文件有——version或——help标志,这是一个快速的无操作,这是有帮助的。

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

这不是一个通用的解决方案,但对于很多用例来说是最简单的方法——在这些用例中,代码需要寻找一个已知的可执行文件,该文件可以安全运行,或者至少可以安全运行给定的标志。

其他回答

因此,基本上您希望在挂载的文件系统中找到一个文件(不一定只在PATH目录中)并检查它是否可执行。这可以转化为以下计划:

枚举本地挂载的文件系统中的所有文件 用名称模式匹配结果 对于找到的每个文件,检查它是否可执行

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

只要记住在windows上指定文件扩展名即可。否则,你必须使用PATHEXT环境变量为windows编写一个非常复杂的is_exe。您可能只想使用FindPath。

哦,你为什么还要费心搜索可执行文件呢?操作系统将作为popen调用的一部分为你做这件事,如果找不到可执行文件,将引发一个异常。您所需要做的就是为给定的操作系统捕获正确的异常。注意,在Windows上,subprocess。如果没有找到exe, 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) 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

对于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 cmd_exists(cmd):
    return shutil.which(cmd) is not None

对于python 3.2及更早版本:

my_command = 'ls'
any(
    (
        os.access(os.path.join(path, my_command), os.X_OK) 
        and os.path.isfile(os.path.join(path, my_command)
    )
    for path in os.environ["PATH"].split(os.pathsep)
)

这是Jay的回答中的一行代码,也是一个lambda func:

cmd_exists = lambda x: any((os.access(os.path.join(path, x), os.X_OK) and os.path.isfile(os.path.join(path, x))) for path in os.environ["PATH"].split(os.pathsep))
cmd_exists('ls')

最后,缩进为函数:

def cmd_exists(cmd, path=None):
    """ test if path contains an executable file with name
    """
    if path is None:
        path = os.environ["PATH"].split(os.pathsep)

    for prefix in path:
        filename = os.path.join(prefix, cmd)
        executable = os.access(filename, os.X_OK)
        is_not_directory = os.path.isfile(filename)
        if executable and is_not_directory:
            return True
    return False

一个重要的问题是“为什么需要测试可执行文件是否存在?”也许你不知道?: -)

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

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

更新:关于操作系统我错了。开始文件是可移植的…这是Windows独有的。在Mac上,你必须运行open命令。Unix上的xdg_open。添加Mac和Unix对os.startfile的支持存在Python问题。

基于请求原谅比请求许可更容易(而且,重要的是,该命令可以安全运行),我会尝试使用它并捕获错误(在本例中是OSError -我检查了文件不存在和文件不可执行,它们都给出了OSError)。

如果可执行文件有——version或——help标志,这是一个快速的无操作,这是有帮助的。

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

这不是一个通用的解决方案,但对于很多用例来说是最简单的方法——在这些用例中,代码需要寻找一个已知的可执行文件,该文件可以安全运行,或者至少可以安全运行给定的标志。