如何找到可执行文件的路径?


81

我需要使用二进制路径设置环境。在外壳中,我可以使用它which来查找路径。python中是否有等效项?这是我的代码。

cmd = ["which","abc"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
res = p.stdout.readlines()
if len(res) == 0: return False
return True

即使在外壳本身中,which它本身也不是检测是否已安装命令的好选择。参考
kojiro

Answers:


93

6
+1,这很酷,是标准库的一部分!请注意,它在Windows上非常受限制-它不会解析PATHEXT,而是假定它应搜索“ .exe”扩展名(缺少批处理文件等)
orip 2014年

2
注意,它不会检查文件是否可执行。
temoto

1
这对我来说在2.7或3.6上不起作用。出现错误,未找到生成模块。
GreenMatt

@temoto尽管它在Windows上找不到适合我的dll文件(我可以PATH通过检查该文件where.exe)。
jpmc26

@GreenMatt,刚刚在3.7中试用过,效果很好。正如其他人所提到的,不要忘记先运行import distutils.spawn
zonksoft

78

我知道这是一个比较老的问题,但是如果您碰巧正在使用Python 3.3+,则可以使用shutil.which(cmd)。您可以在此处找到文档。它具有位于标准库中的优势。

一个例子是这样的:

>>> import shutil
>>> shutil.which("bash")
'/usr/bin/bash'

13

没有执行此操作的命令,但是您可以遍历environ["PATH"]并查看文件是否存在,这实际上是在which做。

import os

def which(file):
    for path in os.environ["PATH"].split(os.pathsep):
        if os.path.exists(os.path.join(path, file)):
                return os.path.join(path, file)

    return None

祝好运!


1
您要谨慎地假设有关pathep字符。
John Percival Hackworth

和路径分隔符,但这只是一个要点。祝好运!
贡萨洛·拉拉尔德

使用os.path.sep代替/os.pathsep代替:
djhaskin987 2014年

2
不要使用“ +”,而应使用os.path.join。查看更多关于stdlib实现(distutils)的投票,以及更多与Twisted项目无关的平台。
即将

感谢os.path.join。扭曲的实现是完全隔离的,似乎与项目的其余部分没有任何相互依存,因此,作为实现,它要好得多(至少比我的要好)
Gonzalo Larralde 2015年


4

您可以尝试以下操作:

import os
import os.path
def which(filename):
    """docstring for which"""
    locations = os.environ.get("PATH").split(os.pathsep)
    candidates = []
    for location in locations:
        candidate = os.path.join(location, filename)
        if os.path.isfile(candidate):
            candidates.append(candidate)
    return candidates

你需要PATHEXT考虑,以及
OriP的

2
在Windows计算机上,我怀疑您可能会寻找文件的确切名称,而不是假设扩展名是。话虽如此,添加一个遍历PATHEXT成员的内部循环并不难。
约翰·珀西瓦尔

3

如果使用shell=True,那么您的命令将在系统外壳中运行,该系统外壳会在路径上自动找到二进制文件:

p = subprocess.Popen("abc", stdout=subprocess.PIPE, shell=True)

即使没有shell=True在路径中查找它,但如果要查找存在哪些可能的命令也无济于事。
Antti Haapala'3

3

这等效于which命令,该命令不仅检查文件是否存在,还检查文件是否可执行:

import os

def which(file_name):
    for path in os.environ["PATH"].split(os.pathsep):
        full_path = os.path.join(path, file_name)
        if os.path.exists(full_path) and os.access(full_path, os.X_OK):
            return full_path
    return None

0

这是先前答案的单行版本:

import os
which = lambda y: next(filter(lambda x: os.path.isfile(x) and os.access(x,os.X_OK),[x+os.path.sep+y for x in os.getenv("PATH").split(os.pathsep)]),None)

像这样使用:

>>> which("ls")
'/bin/ls'

这似乎在Python2中不起作用TypeError: list object is not an iterator
Gibbsoft
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.