3131 Stimmen

Wie kann ich von einem Bash-Skript aus prüfen, ob ein Programm existiert?

Wie kann ich überprüfen, ob ein Programm existiert, und zwar so, dass es entweder einen Fehler zurückgibt und beendet wird oder mit dem Skript fortfährt?

Es sollte eigentlich ganz einfach sein, aber es hat mich nicht weitergebracht.

2 Stimmen

Was ist ein "Programm"? Beinhaltet es Funktionen und Aliasnamen? which gibt für diese den Wert true zurück. type ohne Argumente gibt zusätzlich true für reservierte Wörter und Shell-Builtins zurück. Wenn "Programm" bedeutet "auswählbar in $PATH ", dann siehe diese Antwort .

0 Stimmen

@TomHale Es hängt davon ab, welche Implementierung von which die Sie verwenden; diese wird nicht von der Bash, sondern z.B. von Debian's debianutils bereitgestellt.

4447voto

lhunath Punkte 111281

Antwort

POSIX-kompatibel:

command -v <the_command>

Beispiel für die Verwendung:

if ! command -v <the_command> &> /dev/null
then
    echo "<the_command> could not be found"
    exit
fi

Für Bash-spezifische Umgebungen:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords

Erläuterung

Vermeiden Sie which . Nicht nur, dass es sich um einen externen Prozess handelt, den Sie starten, um sehr wenig zu tun (d. h. Builtins wie hash , type o command sind viel billiger), können Sie sich auch darauf verlassen, dass die eingebauten Programme tatsächlich das tun, was Sie wollen, während die Auswirkungen externer Befehle leicht von System zu System variieren können.

Warum ist das wichtig?

  • Viele Betriebssysteme haben eine which dass setzt nicht einmal einen Exit-Status , d.h. die if which foo wird dort nicht einmal arbeiten und wird siempre berichten, dass foo existiert, auch wenn sie nicht existiert (beachten Sie, dass einige POSIX-Shells dies für hash auch).
  • Viele Betriebssysteme machen which benutzerdefinierte und böse Dinge tun, wie z.B. die Ausgabe ändern oder sich sogar in den Paketmanager einklinken.

Verwenden Sie also nicht which . Verwenden Sie stattdessen eine der folgenden Möglichkeiten:

$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }

(Kleine Randbemerkung: Einige werden behaupten 2>&- ist derselbe 2>/dev/null aber kürzer - dies ist nicht wahr . 2>&- schließt FD 2, was zu einer Fehler im Programm, wenn es versucht, nach stderr zu schreiben, was etwas ganz anderes ist als das erfolgreiche Schreiben nach stderr und das Verwerfen der Ausgabe (und gefährlich!))

Wenn Ihr Rauteknall ist /bin/sh dann sollten Sie sich darum kümmern, was POSIX sagt. type y hash sind die Exit-Codes von POSIX nicht sonderlich gut definiert, und hash wird erfolgreich beendet, wenn der Befehl nicht existiert (ich habe dies nicht mit type noch nicht). command ist der Exit-Status von POSIX gut definiert, so dass es wahrscheinlich am sichersten ist, diesen zu verwenden.

Wenn Ihr Skript Folgendes verwendet bash Allerdings spielen die POSIX-Regeln keine Rolle mehr und beide type y hash vollkommen sicher zu verwenden sind. type hat jetzt eine -P um nur die PATH y hash hat den Nebeneffekt, dass der Speicherort des Befehls mit einem Hash versehen wird (um bei der nächsten Verwendung schneller nachschlagen zu können), was in der Regel eine gute Sache ist, da Sie wahrscheinlich nach seiner Existenz suchen, um ihn tatsächlich zu verwenden.

Hier ein einfaches Beispiel für eine Funktion, die Folgendes ausführt gdate wenn sie existiert, ansonsten date :

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

Alternative mit einem vollständigen Funktionsumfang

Sie können verwenden skripte-gemeinsam um Ihren Bedarf zu decken.

Um zu überprüfen, ob etwas installiert ist, können Sie dies tun:

checkBin <the_command> || errorMessage "This tool requires <the_command>. Install it please, and then run this tool again."

0 Stimmen

Würden Sie mir bitte erklären, was die &>/dev/null y >&2 Teile sind für? Die Linie scheint auch ohne sie gut zu funktionieren. Danke!

48 Stimmen

@Geert: Der &>/dev/null-Teil versteckt die Meldung, die 'type' ausgibt, wenn 'foo' nicht existiert. Das >&2 am echo sorgt dafür, dass die Fehlermeldung an den Standardfehler und nicht an die Standardausgabe geschickt wird, weil das der Konvention entspricht. Beide erscheinen auf Ihrem Terminal, aber Standardfehler ist definitiv die bevorzugte Ausgabe für Fehlermeldungen und unerwartete Warnungen.

7 Stimmen

Das -P Flag funktioniert nicht in 'sh', z.B. stackoverflow.com/questions/2608688/

856voto

nyuszika7h Punkte 13065

Nachfolgend finden Sie einen portablen Weg, um zu prüfen, ob ein Befehl in $PATH et ausführbar ist:

[ -x "$(command -v foo)" ]

Beispiel:

if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi

Die Prüfung auf Ausführbarkeit ist notwendig, weil die Bash eine nicht ausführbare Datei zurückgibt, wenn keine ausführbare Datei mit diesem Namen in $PATH .

Beachten Sie auch, dass, wenn eine nicht ausführbare Datei mit demselben Namen wie die ausführbare Datei früher in $PATH gibt Bindestrich den ersten zurück, auch wenn der zweite ausgeführt würde. Dies ist ein Fehler und verstößt gegen den POSIX-Standard. [ Fehlerbericht ] [ Standard ]

Darüber hinaus schlägt dies fehl, wenn der gesuchte Befehl als Alias definiert wurde.

0 Stimmen

Leider funktioniert das nicht auf älteren bash 3.2

5 Stimmen

Will command -v einen Pfad auch für eine nicht ausführbare Datei erzeugen? Das heißt, ist das -x wirklich notwendig?

5 Stimmen

@einpoklum -x prüft, ob die Datei ausführbar ist, was die Frage war.

234voto

GregV Punkte 2435

Ich stimme mit lhunath überein, dass von der Verwendung von which und seine Lösung ist absolut gültig für Bash-Benutzer . Allerdings, um mehr tragbar zu sein, command -v verwendet werden:

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }

Befehl command ist POSIX-konform. Siehe hier für seine Spezifikation: command - einen einfachen Befehl ausführen

Note : type ist POSIX-konform, aber type -P ist nicht.

3 Stimmen

Wie oben - exit 1; tötet einen xterm, wenn er von dort aus aufgerufen wird.

1 Stimmen

Dies würde auf einem Standard-Sh nicht funktionieren: Sie &> ist keine gültige Umleitungsanweisung.

10 Stimmen

@jyavenard: Die Frage ist getaggt bash daher die prägnantere bash-spezifische Redirect-Notation &>/dev/null . Allerdings stimme ich Ihnen zu, was wirklich wichtig ist, ist die Portabilität, ich habe meine Antwort entsprechend bearbeitet, jetzt mit Standard-sh umzuleiten >/dev/null 2>&1 .

112voto

dreamlax Punkte 91447

Es hängt davon ab, ob Sie wissen wollen, ob es in einem der Verzeichnisse im $PATH oder ob Sie die absolute Position der Variable kennen. Wenn Sie wissen wollen, ob die Variable in der $PATH Variable, verwenden Sie

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

sonst verwenden

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

Die Weiterleitung an /dev/null/ im ersten Beispiel unterdrückt die Ausgabe der which Programm.

30 Stimmen

Aus den in meinem Kommentar genannten Gründen sollten Sie das Wort "welche" wirklich nicht verwenden.

102voto

Josh Strater Punkte 1093

Ich habe in meiner .bashrc eine Funktion definiert, die dies erleichtert.

command_exists () {
    type "$1" &> /dev/null ;
}

Hier ist ein Beispiel für die Verwendung (aus meinem .bash_profile .)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

0 Stimmen

Was bedeutet die &> tun?

11 Stimmen

0 Stimmen

&> ist in Ihrer Version der Bash möglicherweise nicht verfügbar. Der Code von Marcello sollte gut funktionieren; er tut dasselbe.

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