Testen, ob eine ausführbare Datei in Python vorhanden ist?

297

Gibt es in Python eine tragbare und einfache Möglichkeit, um zu testen, ob ein ausführbares Programm vorhanden ist?

Mit einfach meine ich so etwas wie den whichBefehl, der einfach perfekt wäre. Ich möchte PATH nicht manuell durchsuchen oder versuchen, es mit Popen& al auszuführen und zu sehen, ob es fehlschlägt (das mache ich jetzt, aber stell dir vor, es ist launchmissiles)

Piotr Lesnicki
quelle
4
Was ist falsch an der Suche in der Umgebungsvariablen PATH? Was macht Ihrer Meinung nach der UNIX-Befehl 'which'?
Jay
1
Ist das Skript which.py ​​von stdlib ein einfacher Weg?
JFS
@JF - das Skript which.py ​​inkl. mit Python hängt von 'ls' ab und einige der anderen Kommentare weisen darauf hin, dass Piotr nach einer plattformübergreifenden Antwort suchte.
Jay
@ Jay: Danke für den Kommentar. Ich habe Coreutils unter Windows installiert, daher habe ich nicht bemerkt, dass which.py ​​unixspezifisch ist.
JFS
Es gibt auch whichdas Modul eines
Sridhar Ratnakumar

Antworten:

321

Der einfachste Weg, den ich mir vorstellen kann:

def which(program):
    import os
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None

Bearbeiten : Das Codebeispiel wurde aktualisiert und enthält nun eine Logik für die Behandlung von Fällen, in denen das angegebene Argument bereits einen vollständigen Pfad zur ausführbaren Datei enthält, dh "which / bin / ls". Dies ahmt das Verhalten des UNIX-Befehls 'which' nach.

Bearbeiten : Aktualisiert, um os.path.isfile () anstelle von os.path.exists () pro Kommentar zu verwenden.

Bearbeiten : path.strip('"')scheint hier das Falsche zu sein. Weder Windows noch POSIX scheinen zitierte PATH-Elemente zu fördern.

Jay
quelle
Danke Jay, ich akzeptiere deine Antwort, obwohl sie für mich meine Frage negativ beantwortet. In den Bibliotheken gibt es keine solche Funktion, ich muss sie nur schreiben (ich gebe zu, dass meine Formulierung nicht klar genug war, weil ich weiß, was was tut).
Piotr Lesnicki
1
Jay, wenn du deine Antwort gemäß meiner vervollständigst (um 'w' zu haben), damit ich meine entfernen kann.
Piotr Lesnicki
2
Bei einigen Betriebssystemen müssen Sie möglicherweise die Erweiterung der ausführbaren Datei hinzufügen. Unter Ubuntu kann ich beispielsweise schreiben, welches ("scp"), aber unter Windows musste ich welches schreiben ("scp.exe").
Waffleman
13
Ich würde vorschlagen, "os.path.exists" in "os.path.isfile" zu ändern. Andernfalls könnte dies unter Unix fälschlicherweise einem Verzeichnis mit dem gesetzten + x-Bit entsprechen. Ich finde es auch nützlich, dies oben in der Funktion hinzuzufügen: import sys; if sys.platform == "win32" und nicht program.endswith (". exe"): program + = ".exe". Auf diese Weise können Sie unter Windows entweder auf "calc" oder "calc.exe" verweisen, genau wie in einem cmd-Fenster.
Kevin Ivarsen
1
@KevinIvarsen Eine bessere Möglichkeit wäre durch die Werte der sein Looping PATHEXTenv var da commandals gültig ist wie command.comwie scriptvsscript.bat
Lekensteyn
325

Ich weiß, dass dies eine alte Frage ist, aber Sie können sie verwenden distutils.spawn.find_executable. Dies wurde seit Python 2.4 dokumentiert und existiert seit Python 1.6.

import distutils.spawn
distutils.spawn.find_executable("notepad.exe")

Auch Python 3.3 bietet jetzt shutil.which().

Nathan Binkert
quelle
7
Ein sucht win32die distutils.spawn.find_executableImplementierung nur nach .exeder Liste der Erweiterungen, nach denen gesucht wird, anstatt sie zu verwenden %PATHEXT%. Das ist nicht großartig, aber es könnte für alle Fälle funktionieren, die jemand braucht.
Rakslice
7
Beispiel Verwendung:from distutils import spawn php_path = spawn.find_executable("php")
Codefreak
6
Anscheinend distutils.spawnnicht zuverlässig verfügbar: Mit meiner Systeminstallation (/ usr / bin / python) von Python 2.7.6 unter OS X 10.10 erhalte ich:, AttributeError: 'module' object has no attribute 'spawn'obwohl es seltsamerweise auf demselben Computer mit derselben Version von Python funktioniert, aber von eine virtuelle Installation.
Josh Kupershmidt
8
@JoshKupershmidt, stellen Sie sicher import distutils.spawn, oder folgen Sie der from distutils import spawnSyntax und nicht nur import distutils. Andernfalls ist es möglicherweise nicht zugänglich und Sie erhalten die oben genannten AttributeErrorInformationen, auch wenn sie vorhanden sind.
John St. John
39

Für Python 3.2 und früher:

my_command = 'ls'
any(os.access(os.path.join(path, my_command), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))

Dies ist ein Einzeiler von Jays Antwort , auch hier als Lambda-Funktion:

cmd_exists = lambda x: any(os.access(os.path.join(path, x), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))
cmd_exists('ls')

Oder zuletzt als Funktion eingerückt:

def cmd_exists(cmd):
    return any(
        os.access(os.path.join(path, cmd), os.X_OK) 
        for path in os.environ["PATH"].split(os.pathsep)
    )

Für Python 3.3 und höher:

import shutil

command = 'ls'
shutil.which(command) is not None

Als Einzeiler von Jan-Philip Gehrcke Antwort :

cmd_exists = lambda x: shutil.which(x) is not None

Als def:

def cmd_exists(cmd):
    return shutil.which(cmd) is not None
ThorSummoner
quelle
1
Die Version "als Funktion eingerückt" verwendet die Variable, xwo sie sein solltecmd
0x89
Sie müssen auch einen Test hinzufügen, um festzustellen, ob os.path.join(path, cmd)es sich um eine Datei handelt, nein? Schließlich können Verzeichnisse auch das ausführbare Bit gesetzt haben ...
MestreLion
@MestreLion Das klingt nach einem möglichen Fall. Würde es Ihnen etwas ausmachen, dieses Verhalten zu bestätigen und diese Antwort zu aktualisieren? Ich freue mich, diesen Beitrag in ein Community-Wiki zu ändern, wenn das hilft.
ThorSummoner
1
@ThorSummoner: Ich habe es bestätigt, und es erfordert in der Tat den Test für die Datei. Ein einfacher Test:mkdir -p -- "$HOME"/bin/dummy && PATH="$PATH":"$HOME"/bin && python -c 'import os; print any(os.access(os.path.join(path, "dummy"), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))' && rmdir -- "$HOME"/bin/dummy
MestreLion
1
Das Hinzufügen eines einfachen and os.path.isfile(...)zu den entsprechenden Stellen reicht aus, um das zu beheben
MestreLion
19

Denken Sie daran, die Dateierweiterung unter Windows anzugeben. Andernfalls müssen Sie is_exemithilfe von PATHEXTUmgebungsvariablen eine für Windows sehr komplizierte Version schreiben . Möglicherweise möchten Sie nur FindPath verwenden .

OTOH, warum machst du dir überhaupt die Mühe, nach der ausführbaren Datei zu suchen? Das Betriebssystem erledigt dies für Sie im Rahmen des popenAufrufs und löst eine Ausnahme aus, wenn die ausführbare Datei nicht gefunden wird. Sie müssen lediglich die richtige Ausnahme für das jeweilige Betriebssystem abfangen. Beachten Sie, dass unter Windows im subprocess.Popen(exe, shell=True)Hintergrund ein Fehler auftritt, wenn er exenicht gefunden wird.


Einbeziehung PATHEXTin die obige Implementierung von which(in Jays Antwort):

def which(program):
    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK) and os.path.isfile(fpath)

    def ext_candidates(fpath):
        yield fpath
        for ext in os.environ.get("PATHEXT", "").split(os.pathsep):
            yield fpath + ext

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            for candidate in ext_candidates(exe_file):
                if is_exe(candidate):
                    return candidate

    return None
Suraj
quelle
1
Es wurde ein Fehler in der akzeptierten Antwort behoben. Diese Antwort sollte stattdessen oben stehen.
NiTe Luo
Die geschickte Verwendung von yieldin ext_candidatesgab mir ein besseres Verständnis dafür, wie dieses Schlüsselwort funktioniert
Grant Humphries
15

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

Das scheint für mich zu funktionieren:

Herausgegeben auf die Arbeit an Linux, dank Mestreion

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

Wir verwenden hier den eingebauten Befehl typeund überprüfen den Exit-Code. Wenn es keinen solchen Befehl gibt, typewird er mit 1 (oder einem Statuscode ungleich Null) beendet.

Das Bit über stdout und stderr besteht nur darin, die Ausgabe des typeBefehls stumm zu schalten , da wir nur am Exit-Statuscode interessiert sind.

Anwendungsbeispiel:

>>> cmd_exists("jsmin")
True
>>> cmd_exists("cssmin")
False
>>> cmd_exists("ls")
True
>>> cmd_exists("dir")
False
>>> cmd_exists("node")
True
>>> cmd_exists("steam")
False
hasen
quelle
2
Bist du sicher, dass das funktioniert? Es ist ein sehr netter Ansatz, aber es typeist eine eingebaute Shell, keine ausführbare Datei, also subprocess.call()schlägt hier fehl.
MestreLion
1
Hast du es versucht oder theoretisierst du nur? Es funktioniert sowieso auf meinem Mac.
hasen
Ich habe es in Ubuntu 12.04 versucht, es wirft OSError: [Errno 2] No such file or directory. Vielleicht ist in Mac typeein tatsächlicher Befehl
MestreLion
2
Nach einer LOT der Prüfung habe ich , wie man fix gefunden: add shell=Trueund ersetzen ["type", cmd]für"type " + cmd
MestreLion
4
Achtung: Stellen Sie sicher, dass die Variable "cmd" gültige Daten enthält. Wenn es von einer externen Quelle stammt, könnte ein Bösewicht Ihnen "ls; rm -rf /" geben. Ich denke, die In-Python-Lösung (ohne Unterprozess) ist viel besser. Nächster Punkt: Wenn Sie diese Methode häufig aufrufen, ist die Unterprozesslösung viel langsamer, da viele Prozesse erzeugt werden müssen.
Guettli
7

Im os.path- Modul finden Sie einige nützliche Funktionen für Pfadnamen. Um zu überprüfen, ob eine vorhandene Datei ausführbar ist, verwenden Sie os.access (Pfad, Modus) im Modus os.X_OK.

os.X_OK

Wert, der in den mode-Parameter von access () aufgenommen werden soll, um zu bestimmen, ob der Pfad ausgeführt werden kann.

BEARBEITEN: Bei den vorgeschlagenen which()Implementierungen fehlt ein Hinweis - os.path.join()zum Erstellen vollständiger Dateinamen.

Gimel
quelle
Danke, Gimel, im Grunde habe ich meine Antwort: Es gibt keine solche Funktion, ich muss sie manuell ausführen.
Piotr Lesnicki
Verwenden Sie os.access nicht. Die Zugriffsfunktion ist für suid-Programme ausgelegt.
Changming Sun
6

Da es einfacher ist, um Vergebung als um Erlaubnis zu bitten, würde ich einfach versuchen, sie zu verwenden und den Fehler abzufangen (OSError in diesem Fall - Ich habe überprüft, ob eine Datei nicht vorhanden ist und die Datei nicht ausführbar ist und beide OSError geben).

Es hilft, wenn die ausführbare Datei so etwas wie ein --versionFlag hat, das ein schnelles No-Op ist.

import subprocess
myexec = "python2.8"
try:
    subprocess.call([myexec, '--version']
except OSError:
    print "%s not found on path" % myexec

Dies ist keine allgemeine Lösung, aber der einfachste Weg für viele Anwendungsfälle - solche, bei denen der Code nach einer einzigen bekannten ausführbaren Datei suchen muss.

Hamish Downer
quelle
3
Es ist zu gefährlich, --versionein Programm namens aufzurufen launchmissiles!
xApple
1
+1, ich mag diesen Ansatz. EAFP ist eine goldene Python-Regel. Warum sollten Sie wissen, ob eine Benutzeroberfläche vorhanden ist, launchmissieses sei denn, Sie möchten Raketen abschießen? Besser, es auszuführen und auf Exit-Status / Ausnahmen zu
reagieren
Das Problem bei dieser Methode ist, dass die Ausgabe auf der Konsole gedruckt wird. Wenn Sie Pipes und Shell = True verwenden, wird der OSError nie ausgelöst
Nick Humrich
Unter macOS haben Sie auch ausführbare Stub-Dateien, z. B. für gitdie Sie wahrscheinlich nicht blind ausführen möchten.
Bob Aman
5

Ich weiß, dass ich hier ein bisschen ein Nekromant bin, aber ich bin über diese Frage gestolpert und die akzeptierte Lösung hat nicht in allen Fällen für mich funktioniert. Ich dachte, es könnte nützlich sein, sie trotzdem einzureichen. Insbesondere die Erkennung des "ausführbaren" Modus und die Anforderung, die Dateierweiterung bereitzustellen. Darüber hinaus funktionieren sowohl Python3.3 shutil.which(verwendet PATHEXT) als auch Python2.4 + distutils.spawn.find_executable(versucht nur das Hinzufügen '.exe') nur in einer Teilmenge von Fällen.

Also schrieb ich eine "Super" -Version (basierend auf der akzeptierten Antwort und dem PATHEXTVorschlag von Suraj). Diese Version von whicherledigt die Aufgabe etwas gründlicher und probiert zuerst eine Reihe von "Breitphasen" -Breiten-First-Techniken aus und versucht schließlich feinkörnigere Suchen über den PATHRaum:

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):
    """ Simulates unix `which` command. Returns absolute path if program found """
    def is_exe(fpath):
        """ Return true if fpath is a file we have access to that is executable """
        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):
        """ Return list of (filename, extension) tuples which match the search_filename"""
        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)

    # is a path: try direct program path
    if fpath:
        if is_exe(program):
            return program
    elif "win" in sys.platform:
        # isnt a path: try fname in current directory on 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)

    # try append program path per directory
    for path in paths:
        exe_file = os.path.join(path, program)
        if is_exe(exe_file):
            return exe_file

    # try with known executable extensions per program path per directory
    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

    # try search program name with "soft" extension search
    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 nicht für mich Arbeit in diesem Fall, da es gab Dateien wie meld.1, meld.ico, meld.doapusw. auch in dem Verzeichnis, von denen stattdessen zurückgegeben wurden (vermutlich lexikographisch ersten seit) , weil der ausführbare Test in der akzeptierten Antwort war unvollständig und geben Fehlalarm.

Preet Kukreti
quelle
2

Ich habe in StackOverflow etwas gefunden, das das Problem für mich gelöst hat. Dies funktioniert, vorausgesetzt, die ausführbare Datei verfügt über eine Option (wie --help oder --version), die etwas ausgibt und einen Exit-Status von Null zurückgibt. Siehe Ausgabe in Python-Aufrufen an ausführbare Dateien unterdrücken - das "Ergebnis" am Ende des Codeausschnitts in dieser Antwort ist Null, wenn sich die ausführbare Datei im Pfad befindet, andernfalls ist es höchstwahrscheinlich 1.

Somesh
quelle
2

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

try: subprocess.check_output('which executable',shell=True)
except: sys.exit('ERROR: executable not found')
jaap
quelle
Sorry Jaap, aber diese Lösung funktioniert nur, wenn die ausführbare Datei keinen Exit-Code 1 aufruft, wenn sie falsch aufgerufen wird. So funktioniert es beispielsweise für "dir" und "ls", aber wenn Sie etwas ausführen, für das eine Konfiguration erforderlich ist, wird es unterbrochen, obwohl die ausführbare Datei vorhanden ist.
Spedge
1
Was genau meinst du mit "Konfiguration erforderlich"? An sich führt 'which' eigentlich nichts aus, sondern überprüft nur den PATH auf das Vorhandensein einer ausführbaren Datei mit diesem Namen (man which).
Jaap
1
Ohh, Sie verwenden also "which", um die ausführbare Datei zu finden. Das funktioniert also nur unter Linux / Unix?
Spedge
1
Verwenden command -v executableoder type executableuniversell sein. Es gibt Fälle, in denen auf Macs die erwarteten Ergebnisse nicht zurückgegeben werden.
RJ
1

Eine wichtige Frage lautet: " Warum müssen Sie testen, ob eine ausführbare Datei vorhanden ist?" Vielleicht nicht? ;-);

Vor kurzem brauchte ich diese Funktionalität, um den Viewer für PNG-Dateien zu starten. Ich wollte einige vordefinierte Viewer durchlaufen und den ersten ausführen, der existiert. Zum Glück bin ich rübergekommen os.startfile. Es ist viel besser! Einfach, portabel und verwendet den Standard- Viewer auf dem System:

>>> os.startfile('yourfile.png')

Update: Ich habe mich geirrt os.startfile, portabel zu sein ... Es ist nur Windows. Auf dem Mac müssen Sie den openBefehl ausführen . Und xdg_openunter Unix. Es gibt ein Python-Problem beim Hinzufügen von Mac- und Unix-Unterstützung für os.startfile.

Asche
quelle
1

Sie können die externe Bibliothek "sh" ( http://amoffat.github.io/sh/ ) ausprobieren .

import sh
print sh.which('ls')  # prints '/bin/ls' depending on your setup
print sh.which('xxx') # prints None
jung rhew
quelle
1

Windows-Unterstützung hinzugefügt

def which(program):
    path_ext = [""];
    ext_list = None

    if sys.platform == "win32":
        ext_list = [ext.lower() for ext in os.environ["PATHEXT"].split(";")]

    def is_exe(fpath):
        exe = os.path.isfile(fpath) and os.access(fpath, os.X_OK)
        # search for executable under windows
        if not exe:
            if ext_list:
                for ext in ext_list:
                    exe_path = "%s%s" % (fpath,ext)
                    if os.path.isfile(exe_path) and os.access(exe_path, os.X_OK):
                        path_ext[0] = ext
                        return True
                return False
        return exe

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

    if fpath:
        if is_exe(program):
            return "%s%s" % (program, path_ext[0])
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return "%s%s" % (exe_file, path_ext[0])
    return None
Wukong
quelle
0

Sie können feststellen, ob eine Datei mit dem OS-Modul vorhanden ist. Insbesondere eine ausführbare Datei scheint ziemlich unportabel zu sein, wenn man bedenkt, dass viele Dinge unter nix ausführbar sind, die nicht unter Windows sind, und umgekehrt.

Dustin Getz
quelle
0

Es scheint, dass die offensichtliche Wahl "welche" ist, die die Ergebnisse über popen analysiert, aber Sie könnten es auch anders mit der os-Klasse simulieren. In Pseudopython würde es so aussehen:

for each element r in path:
    for each file f in directory p:
        if f is executable:
           return True
Charlie Martin
quelle
Ich würde vorsichtig sein, wenn ich einen "which" -Befehl mit os.exec oder ähnlichem ausführen würde. Es ist nicht nur oft langsam (wenn die Leistung ein Problem darstellt), sondern wenn Sie eine Variable als Teil Ihrer Exec-Zeichenfolge verwenden, wird die Sicherheit zu einem Problem. Jemand könnte sich in ein "rm -rf /" schleichen.
Parappa
1
Was, da wir die Funktion os.popen verwenden würden, um einen vom Programm erstellten Befehl auszuführen, nicht wirklich zutrifft, nein?
Charlie Martin
2
Danke, aber ich bin mir nicht sicher, ob 'welches' unter Windows und dergleichen existiert. Ich wollte im Wesentlichen wissen, ob es in der
Standardbibliothek
In Standard-Windows-Installationen gibt es immer noch keinen whichBefehl. Es gibt eine UnxUtils-Version, aber Sie müssen die Erweiterung kennen / angeben, sonst wird das Programm nicht gefunden.
Tobias
0

Grundsätzlich möchten Sie also eine Datei im bereitgestellten Dateisystem finden (nicht unbedingt nur in PATH-Verzeichnissen) und prüfen, ob sie ausführbar ist. Dies führt zu folgendem Plan:

  • Zählen Sie alle Dateien in lokal bereitgestellten Dateisystemen auf
  • Ergebnisse mit Namensmuster abgleichen
  • Überprüfen Sie für jede gefundene Datei, ob sie ausführbar ist

Ich würde sagen, dies auf tragbare Weise zu tun, erfordert viel Rechenleistung und Zeit. Ist es wirklich das, was du brauchst?

zgoda
quelle
0

In einer Standard-Python-Distribution (z . B. unter Windows ) gibt es ein which.py- Skript '\PythonXX\Tools\Scripts\which.py'.

BEARBEITEN: which.pyhängt lsdavon ab, dass es nicht plattformübergreifend ist.

jfs
quelle
0

Keines der vorherigen Beispiele funktioniert auf allen Plattformen. Normalerweise funktionieren sie unter Windows nicht, da Sie ohne die Dateierweiterung ausführen und eine neue Erweiterung registrieren können. Wenn beispielsweise Python unter Windows gut installiert ist, reicht es aus, 'file.py' auszuführen, und es funktioniert.

Die einzige gültige und tragbare Lösung bestand darin, den Befehl auszuführen und den Fehlercode anzuzeigen. Jede anständige ausführbare Datei sollte eine Reihe von aufrufenden Parametern haben, die nichts bewirken.

Sorin
quelle
-3

Verwenden der Python-Fabric-Bibliothek:

from fabric.api import *

def test_cli_exists():
    """
    Make sure executable exists on the system path.
    """
    with settings(warn_only=True):
        which = local('which command', capture=True)

    if not which:
        print "command does not exist"

    assert which
frodopwns
quelle
2
Dies ist ein sehr schlechter Vorschlag. Sie machen das Programm buchstäblich von der Remote-Ausführungsbibliothek abhängig , um ein lokales Programm zu erzeugen (was Python stdlib problemlos kann), und Sie sind außerdem davon abhängig, which(1)welches nicht auf allen Systemen vorhanden ist.
Michał Górny