377 Stimmen

Überprüfen Sie, ob eine ausführbare Datei in Python vorhanden ist?

In Python gibt es eine portable und einfache Möglichkeit zu testen, ob ein ausführbares Programm existiert?

Mit einfach meine ich etwas wie den which-Befehl, der einfach perfekt wäre. Ich möchte nicht manuell im PATH suchen oder etwas probieren, das versucht, es mit Popen & Co. auszuführen und zu sehen, ob es fehlschlägt (das ist das, was ich gerade mache, aber stelle dir vor, es ist launchmissiles)

4 Stimmen

Was ist falsch daran, nach der PATH-Umgebungsvariablen zu suchen? Was denkst du, was das UNIX-Befehl 'which' tut?

1 Stimmen

Ist das which.py Skript aus der Standardbibliothek ein einfacher Weg?

0 Stimmen

@J.F. - Das which.py-Skript, das mit Python enthalten ist, hängt von 'ls' ab, und einige der anderen Kommentare deuten darauf hin, dass Piotr nach einer plattformübergreifenden Antwort gesucht hat.

14voto

hasen Punkte 154413

Für *nix-Plattformen (Linux und OS X)

Dies scheint für mich zu funktionieren:

Bearbeitet um auf Linux zu funktionieren, danke an Mestreion

def cmd_exists(cmd):
    return subprocess.call("type " + cmd, shell=True, 
        stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0

Was wir hier tun, ist das Verwenden des integrierten Befehls type und das Überprüfen des Exit-Codes. Wenn es keinen solchen Befehl gibt, wirdtype mit 1 beendet (oder jedenfalls mit einem Nicht-Null-Statuscode).

Der Teil über stdout und stderr dient nur dazu, die Ausgabe des type-Befehls stummzuschalten, da wir nur am Exit-Statuscode interessiert sind.

Beispielverwendung:

>>> cmd_exists("jsmin")
True
>>> cmd_exists("cssmin")
False
>>> cmd_exists("ls")
True
>>> cmd_exists("dir")
False
>>> cmd_exists("node")
True
>>> cmd_exists("steam")
False

11voto

Hamish Downer Punkte 15913

Auf der Grundlage, dass es einfacher ist, um Vergebung zu bitten als um Erlaubnis (und, was wichtig ist, dass der Befehl sicher auszuführen ist), würde ich einfach versuchen, ihn zu benutzen und den Fehler abzufangen (OSError in diesem Fall - ich habe überprüft, ob die Datei nicht existiert und die Datei nicht ausführbar ist und beide geben OSError).

Es hilft, wenn das ausführbare Programm etwas wie eine --version oder --help Flagge hat, die ein schnelles No-Op ist.

import subprocess
myexec = "python2.8"
try:
    subprocess.call([myexec, '--version']
except OSError:
    print "%s nicht im Pfad gefunden" % myexec

Dies ist keine allgemeine Lösung, aber es wird für viele Anwendungsfälle der einfachste Weg sein - diejenigen, bei denen der Code nach einem einzigen bekannten und sicheren auszuführenden Programm suchen muss, oder zumindest sicher auszuführen ist, mit einer bestimmten Flagge.

7voto

gimel Punkte 78080

Siehe os.path Modul für einige nützliche Funktionen zu Pfadnamen. Um zu prüfen, ob eine vorhandene Datei ausführbar ist, verwenden Sie os.access(path, mode), mit dem os.X_OK Modus.

os.X_OK

Wert, der im Modusparameter von access() enthalten sein soll, um zu bestimmen, ob der Pfad ausgeführt werden kann.

BEARBEITEN: Die vorgeschlagenen which() Implementierungen fehlen ein wichtiger Hinweis - die Verwendung von os.path.join() zum Aufbau vollständiger Dateinamen.

5voto

Preet Kukreti Punkte 8257

Ich weiß, dass ich hier ein wenig wie ein Nekromant bin, aber ich bin auf diese Frage gestoßen und die akzeptierte Lösung hat für mich nicht in allen Fällen funktioniert. Ich dachte, es wäre trotzdem nützlich, sie einzureichen. Insbesondere die Erkennung des "ausführbaren" Modus und die Notwendigkeit, die Dateierweiterung anzugeben. Darüber hinaus funktionieren sowohl shutil.which von python3.3 (verwendet PATHEXT) als auch distutils.spawn.find_executable von python2.4+ (versucht nur '.exe' hinzuzufügen) nur in einem Teil der Fälle.

Also habe ich eine "Super"-Version geschrieben (basierend auf der akzeptierten Antwort und dem Vorschlag von Suraj zur Verwendung von PATHEXT). Diese Version von which erledigt die Aufgabe etwas gründlicher und probiert zuerst eine Reihe von "Breitphasen"-Breitensuchtechniken aus und versucht schließlich feingranuliertere Suchen im PATH-Raum:

import os
import sys
import stat
import tempfile

def is_case_sensitive_filesystem():
    tmphandle, tmppath = tempfile.mkstemp()
    is_insensitive = os.path.exists(tmppath.upper())
    os.close(tmphandle)
    os.remove(tmppath)
    return not is_insensitive

_IS_CASE_SENSITIVE_FILESYSTEM = is_case_sensitive_filesystem()

def which(program, case_sensitive=_IS_CASE_SENSITIVE_FILESYSTEM):
    """ Simuliert das Unix 'which' Kommando. Gibt den absoluten Pfad zurück, wenn das Programm gefunden wurde """
    def is_exe(fpath):
        """ Gibt true zurück, wenn fpath eine ausführbare Datei ist, auf die wir zugreifen können """
        accessmode = os.F_OK | os.X_OK
        if os.path.exists(fpath) and os.access(fpath, accessmode) and not os.path.isdir(fpath):
            filemode = os.stat(fpath).st_mode
            ret = bool(filemode & stat.S_IXUSR or filemode & stat.S_IXGRP or filemode & stat.S_IXOTH)
            return ret

    def list_file_exts(directory, search_filename=None, ignore_case=True):
        """ Gibt eine Liste von Tupeln (Dateiname, Erweiterung) zurück, die zum search_filename passen """
        if ignore_case:
            search_filename = search_filename.lower()
        for root, dirs, files in os.walk(path):
            for f in files:
                filename, extension = os.path.splitext(f)
                if ignore_case:
                    filename = filename.lower()
                if not search_filename or filename == search_filename:
                    yield (filename, extension)
            break

    fpath, fname = os.path.split(program)

    # ist ein Pfad: versuche direkten Programm-Pfad
    if fpath:
        if is_exe(program):
            return program
    elif "win" in sys.platform:
        # kein Pfad: versuche fname im aktuellen Verzeichnis unter Windows
        if is_exe(fname):
            return program

    paths = [path.strip('"') for path in os.environ.get("PATH", "").split(os.pathsep)]
    exe_exts = [ext for ext in os.environ.get("PATHEXT", "").split(os.pathsep)]
    if not case_sensitive:
        exe_exts = map(str.lower, exe_exts)

    # versuche Programm-Pfad pro Verzeichnis anzuhängen
    for path in paths:
        exe_file = os.path.join(path, program)
        if is_exe(exe_file):
            return exe_file

    # versuche mit bekannten ausführbaren Erweiterungen pro Programm-Pfad pro Verzeichnis
    for path in paths:
        filepath = os.path.join(path, program)
        for extension in exe_exts:
            exe_file = filepath+extension
            if is_exe(exe_file):
                return exe_file

    # versuche Programmnamen mit "weicher" Erweiterungssuche zu suchen
    if len(os.path.splitext(fname)[1]) == 0:
        for path in paths:
            file_exts = list_file_exts(path, fname, not case_sensitive)
            for file_ext in file_exts:
                filename = "".join(file_ext)
                exe_file = os.path.join(path, filename)
                if is_exe(exe_file):
                    return exe_file

    return None

Die Verwendung sieht folgendermaßen aus:

>>> which.which("meld")
'C:\\Program Files (x86)\\Meld\\meld\\meld.exe'

Die akzeptierte Lösung hat in meinem Fall nicht funktioniert, da Dateien wie meld.1, meld.ico, meld.doap usw. auch im Verzeichnis vorhanden waren, von denen eine zurückgegeben wurde (vermutlich da lektografisch zuerst), weil der ausführbare Test in der akzeptierten Antwort unvollständig war und falsche Positiven lieferte.

2voto

jaap Punkte 5131

Dies scheint einfach genug zu sein und funktioniert sowohl in Python 2 als auch in 3

try: subprocess.check_output('which ausführbar',shell=True)
except: sys.exit('FEHLER: ausführbar nicht gefunden')

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X