Jak znaleźć ścieżkę do pliku wykonywalnego?

84

Muszę skonfigurować środowisko ze ścieżką do pliku binarnego. W powłoce mogę whichznaleźć ścieżkę. Czy jest odpowiednik w Pythonie? To jest mój kod.

cmd = ["which","abc"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
res = p.stdout.readlines()
if len(res) == 0: return False
return True
prosseek
źródło
Nawet w samej powłoce sama w whichsobie nie jest dobrym wyborem do wykrywania, czy polecenie jest zainstalowane. Odniesienie
kojiro

Odpowiedzi:

94

Jest distutils.spawn.find_executable().

zonksoft
źródło
6
+1, to jest fajne i jest częścią standardowej biblioteki! Należy pamiętać, że jest bardzo ograniczony w systemie Windows - nie analizuje PATHEXT, zamiast tego zakłada, że ​​powinien wyszukiwać rozszerzenie „.exe” (brakujące pliki wsadowe itp.)
orip
2
Uważaj, to nie sprawdza, czy plik jest wykonywalny.
temoto
1
To nie zadziałało dla mnie w wersji 2.7 lub 3.6. Dało to błąd, że nie znaleziono modułu odradzania.
GreenMatt
@temoto A jednak, mimo, że nie znajdzie plik DLL (który mogę sprawdzić jest PATHpoprzez where.exe) dla mnie na Windows.
jpmc26
@GreenMatt, właśnie wypróbowany na 3.7, działa dobrze. Jak wspominali inni, nie zapomnij uruchomić import distutils.spawnnajpierw.
zonksoft
82

Wiem, że to starsze pytanie, ale jeśli używasz Pythona 3.3+, możesz użyć shutil.which(cmd). Dokumentację znajdziesz tutaj . Ma tę zaletę, że znajduje się w standardowej bibliotece.

Przykład mógłby wyglądać tak:

>>> import shutil
>>> shutil.which("bash")
'/usr/bin/bash'
iLoveTux
źródło
13

Nie ma polecenia, aby to zrobić, ale możesz iterować environ["PATH"]i sprawdzić, czy plik istnieje, i tak właśnie whichjest.

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

Powodzenia!

Gonzalo Larralde
źródło
1
Chcesz być ostrożny, przyjmując założenia co do postaci ścieżki.
John Percival Hackworth
i separator ścieżki, ale to tylko dziwactwo, aby zwrócić uwagę. Powodzenia!
Gonzalo Larralde
użyj os.path.sepzamiast /i os.pathsepzamiast:
djhaskin987
2
Nie używaj „+”, użyj os.path.join. Zobacz więcej pozytywnie ocenionych odpowiedzi dotyczących implementacji standardowej biblioteki (distutils) i bardziej niezależnej od platformy projektu Twisted.
benjaoming
dzięki za os.path.join. Skręcona implementacja jest całkowicie izolowana, nie wydaje się mieć żadnych współzależności z resztą projektu, więc jako implementacja jest znacznie lepsza (przynajmniej niż moja)
Gonzalo Larralde
4

Możesz spróbować czegoś takiego:

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
John Percival Hackworth
źródło
Musisz również wziąć PATHEXTpod uwagę
orip
2
Podejrzewam, że na komputerze z systemem Windows prawdopodobnie szukałbyś dokładnej nazwy pliku, zamiast zakładać rozszerzenia. Mając to na uwadze, nie byłoby trudno dodać wewnętrzną pętlę, która iteruje po elementach PATHEXT.
John Percival Hackworth,
3

Jeśli użyjesz shell=True, twoje polecenie zostanie uruchomione przez powłokę systemową, która automatycznie znajdzie plik binarny na ścieżce:

p = subprocess.Popen("abc", stdout=subprocess.PIPE, shell=True)
Greg Hewgill
źródło
Nawet bez shell=Trueniego jest sprawdzany w ścieżce, ale nie pomaga, jeśli chcesz dowiedzieć się, które z możliwych poleceń istnieje.
Antti Haapala
3

Jest to odpowiednik polecenia which, które nie tylko sprawdza, czy plik istnieje, ale także czy jest wykonywalny:

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
o9000
źródło
0

Oto jednowierszowa wersja wcześniejszych odpowiedzi:

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)

używane tak:

>>> which("ls")
'/bin/ls'
Anonimowy
źródło
To nie wydaje się do pracy w python2, TypeError: list object is not an iterator.
Gibbsoft