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

Nawet w samej powłoce sama w whichsobie nie jest dobrym wyborem do wykrywania, czy polecenie jest zainstalowane. Odniesienie
kojiro

Odpowiedzi:


94

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'

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!


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

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)

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

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'

To nie wydaje się do pracy w python2, TypeError: list object is not an iterator.
Gibbsoft
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.