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.
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.
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
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?
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).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
}
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."
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!
@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.
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.
Will command -v
einen Pfad auch für eine nicht ausführbare Datei erzeugen? Das heißt, ist das -x wirklich notwendig?
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.
Dies würde auf einem Standard-Sh nicht funktionieren: Sie &> ist keine gültige Umleitungsanweisung.
@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
.
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.
&>
ist in Ihrer Version der Bash möglicherweise nicht verfügbar. Der Code von Marcello sollte gut funktionieren; er tut dasselbe.
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.
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 .1 Stimmen
Ebenfalls relevant ist Wie kann man mit 'hash -r' alle Shells aktualisieren? y Wann sollen ausführbare Dateien in $PATH mit der Bash aufbereitet werden?
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.