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

Selbst in der Shell selbst whichist es keine gute Wahl, um festzustellen, ob ein Befehl installiert ist. Referenz
Kojiro

Antworten:


93

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'

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!


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


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

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)

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

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'

Dies scheint in Python2 nicht zu funktionieren TypeError: list object is not an iterator.
Gibbsoft
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.