Wie finde ich den Pfad für eine ausführbare Datei?

81

Ich muss die Umgebung mit dem Pfad zu einer Binärdatei einrichten. In der Shell kann ich whichden Pfad finden. Gibt es ein Äquivalent in Python? Das ist mein Code.

cmd = ["which","abc"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
res = p.stdout.readlines()
if len(res) == 0: return False
return True
prosseek
quelle
Selbst in der Shell selbst whichist es keine gute Wahl, um festzustellen, ob ein Befehl installiert ist. Referenz
Kojiro

Antworten:

93

Es gibt distutils.spawn.find_executable().

zonksoft
quelle
6
+1, das ist cool und Teil der Standardbibliothek! Beachten Sie, dass es unter Windows sehr eingeschränkt ist - es analysiert PATHEXT nicht, sondern geht davon aus, dass nach einer Erweiterung '.exe' gesucht werden sollte (fehlende Batch-Dateien usw.)
orip
2
Beachten Sie, dass nicht überprüft wird, ob die Datei ausführbar ist.
Temoto
1
Dies hat bei 2.7 oder 3.6 bei mir nicht funktioniert. Es gab einen Fehler, dass das Spawn-Modul nicht gefunden wurde.
GreenMatt
@temoto Und doch trotz , dass es nicht eine DLL - Datei (die ich überprüfen kann auf bin PATHüber where.exe) für mich unter Windows.
jpmc26
@GreenMatt, gerade in 3.7 ausprobiert, funktioniert einwandfrei. Vergessen Sie nicht, zuerst zu rennen, wie von anderen erwähnt import distutils.spawn.
Zonksoft
78

Ich weiß, dass dies eine ältere Frage ist, aber wenn Sie Python 3.3+ verwenden, können Sie diese verwenden shutil.which(cmd). Die Dokumentation finden Sie hier . Es hat den Vorteil, in der Standardbibliothek zu sein.

Ein Beispiel wäre wie folgt:

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

Es gibt keinen Befehl, um dies zu tun, aber Sie können durchlaufen environ["PATH"]und prüfen , ob die Datei vorhanden ist, was tatsächlich der whichFall ist.

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

Viel Glück!

Gonzalo Larralde
quelle
1
Sie möchten vorsichtig sein und Annahmen über den Pathsep-Charakter treffen.
John Percival Hackworth
und Pfadtrennzeichen, aber dies ist nur eine Eigenart, um einen Punkt zu machen. Viel Glück!
Gonzalo Larralde
Verwenden Sie os.path.sepanstelle von /und os.pathsepanstelle von:
djhaskin987
2
Verwenden Sie nicht '+', sondern os.path.join. Weitere Antworten für eine stdlib-Implementierung (distutils) und eine plattformunabhängigere vom Twisted-Projekt.
benjaoming
danke für os.path.join. Die verdrehte Implementierung ist vollständig isoliert, scheint keine gegenseitige Abhängigkeit vom Rest des Projekts zu haben, daher ist sie als Implementierung viel besser (als zumindest meine)
Gonzalo Larralde
13

( Ähnliche Frage )

Siehe die Twisted-Implementierung: twisted.python.procutils.which

orip
quelle
Danke, ich werde es benutzen.
Jonaprieto
Die Sache dabei ist, dass das Twisted-Modul installiert werden muss, was unter Windows möglicherweise schmerzhaft sein kann (selbst bei Christoph Gohlkes Rädern).
Agi Hammerthief
1
Die Verbindung zur Twisted-Implementierung ist unterbrochen. Sieht so aus, als ob es hier zu finden ist: github.com/twisted/twisted/blob/trunk/src/twisted/python/…
rkersh
4

Sie könnten Folgendes versuchen:

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
quelle
Sie müssen auch PATHEXTberücksichtigen
orip
2
Ich vermute, dass Sie auf einem Windows-Computer wahrscheinlich nach dem genauen Namen der Datei suchen würden, anstatt die Erweiterungen anzunehmen. Wenn dies gesagt ist, wäre es nicht schwer, eine innere Schleife hinzuzufügen, die über die Mitglieder von PATHEXT iteriert.
John Percival Hackworth
3

Wenn Sie verwenden shell=True, wird Ihr Befehl über die System-Shell ausgeführt, die automatisch die Binärdatei auf dem Pfad findet:

p = subprocess.Popen("abc", stdout=subprocess.PIPE, shell=True)
Greg Hewgill
quelle
Auch ohne wird shell=Truees im Pfad nachgeschlagen, aber es hilft nicht, wenn Sie herausfinden möchten, welcher der möglichen Befehle vorhanden ist.
Antti Haapala
3

Dies entspricht dem Befehl which, der nicht nur prüft, ob die Datei vorhanden ist, sondern auch, ob sie ausführbar ist:

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
quelle
0

Hier ist eine einzeilige Version früherer Antworten:

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)

wie folgt verwendet:

>>> which("ls")
'/bin/ls'
Anonym
quelle
Dies scheint in Python2 nicht zu funktionieren TypeError: list object is not an iterator.
Gibbsoft