Як я можу знайти шлях до виконуваного файлу?


84

Мені потрібно налаштувати середовище із шляхом до двійкового файлу. У оболонці я можу 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собі не є вдалим вибором для виявлення встановленої команди. Довідка
Коджіро

Відповіді:


94

6
+1, це круто і є частиною стандартної бібліотеки! Майте на увазі, що він дуже обмежений для Windows - він не аналізує PATHEXT, натомість припускає, що він повинен шукати розширення .exe (відсутні
командні

2
Остерігайтеся, що він не перевіряє, чи виконуваний файл.
temoto

1
Це не спрацювало у мене на 2.7 або 3.6. Це призвело до помилки, оскільки модуль spawn не знайдений.
GreenMatt

@temoto І все ж незважаючи на те що він не знайде файл DLL (що я можу перевірити це на PATHчерез where.exe) для мене в Windows.
jpmc26,

@GreenMatt, щойно спробував 3.7, чудово працює. Як згадували інші, не забувайте бігти import distutils.spawnпершими.
zonksoft

82

Я знаю, що це давнє запитання, але якщо ви випадково використовуєте 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
Ви хочете бути обережними, роблячи припущення щодо символу pathsep.
Джон Персіваль Хекворт,

та роздільник шляхів, але це лише химерність, щоб встановити точку. Удачі!
Gonzalo Larralde

використовувати os.path.sepзамість /та os.pathsepзамість:
djhaskin987

2
Не використовуйте '+', використовуйте os.path.join. Дивіться більше схвалених відповідей щодо реалізації stdlib (distutils) та більш незалежної від платформи програми Twisted.
benjaoming

дякую за os.path.join. Покручена реалізація повністю ізольована, схоже, не має ніякої взаємозалежності з рештою проекту, тому як реалізація вона набагато краща (принаймні моя)
Гонсало Ларральде,

13

( Подібне запитання )

Дивіться реалізацію Twisted: twisted.python.procutils.which


Справа в тому, що він вимагає встановлення модуля Twisted, який може бути болючим у Windows (навіть на колесах Крістофа Гольке).
Agi Hammerthief

1
Посилання на реалізацію Twisted порушено. Схоже, його можна знайти тут: github.com/twisted/twisted/blob/trunk/src/twisted/python/…
rkersh

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до уваги
орип

2
На машині з Windows я підозрюю, що ви, швидше за все, будете шукати точну назву файлу, на відміну від припущення про розширення. З урахуванням цього, не складно буде додати внутрішній цикл, який повторюється над членами PATHEXT.
Джон Персіваль Хекворт

3

Якщо ви використовуєте shell=True, тоді ваша команда буде запущена через системну оболонку, яка автоматично знайде двійковий файл на шляху:

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

Навіть без shell=Trueнього його шукають у шляху, але це не допомагає, якщо ви хочете знайти, яка з можливих команд існує.
Antti Haapala

3

Це еквівалент команди, яка не тільки перевіряє, чи існує файл, але й чи є він виконуваним:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.