Wie würde ich bestätigen, dass ein Programm existiert, so dass entweder ein Fehler zurückgegeben und beendet wird oder mit dem Skript fortgefahren wird?
Es scheint, als ob es leicht sein sollte, aber es hat mich gestampft.
Wie würde ich bestätigen, dass ein Programm existiert, so dass entweder ein Fehler zurückgegeben und beendet wird oder mit dem Skript fortgefahren wird?
Es scheint, als ob es leicht sein sollte, aber es hat mich gestampft.
POSIX-kompatibel:
command -v <the_command>
Zum bash
spezifische Umgebungen:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
Vermeiden which
. Es ist nicht nur ein externer Prozess, den Sie starten, um sehr wenig zu tun (dh Builtins wie hash
, type
oder command
sind viel billiger), können Sie sich auch darauf verlassen, dass die Built-Ins tatsächlich tun, was Sie wollen, während die Auswirkungen von externen Befehlen leicht von System zu System variieren können.
Warum kümmern?
which
Das Nicht einmal einen Exit-Status setzen, was bedeutet if which foo
wird dort nicht einmal arbeiten und werden immer melde das foo
existiert, auch wenn dies nicht der Fall ist (beachten Sie, dass einige POSIX-Shells dies zu tun scheinen) hash
auch).which
tun Sie benutzerdefinierte und böse Sachen wie die Ausgabe ändern oder sogar in den Paketmanager einhaken.Also, nicht benutzen which
. Verwenden Sie stattdessen eines von diesen:
$ 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 Randnotiz: Einige werden vorschlagen 2>&-
ist dasselbe 2>/dev/null
aber kürzer - das ist unwahr. 2>&-
schließt FD 2, was ein verursacht Error in dem Programm, wenn es versucht, in Stderr zu schreiben, was sehr unterschiedlich ist, erfolgreich zu schreiben und die Ausgabe zu verwerfen (und gefährlich!))
Wenn dein Hash-Knall ist /bin/sh
dann sollten Sie sich darum kümmern, was POSIX sagt. type
und hash
Die Exit-Codes von POSIX sind nicht besonders gut definiert hash
Es wird gesehen, dass der Befehl erfolgreich beendet wird, wenn der Befehl nicht existiert type
noch). command
Der Exit-Status ist von POSIX gut definiert, so dass einer wahrscheinlich der sicherste ist.
Wenn das Skript verwendet wird bash
Allerdings sind POSIX-Regeln nicht mehr wichtig und beides type
und hash
werden vollkommen sicher zu bedienen. type
jetzt hat a -P
nur das zu suchen PATH
und hash
hat den Nebeneffekt, dass die Position des Befehls gehashed wird (für eine schnellere Suche, wenn Sie das nächste Mal verwenden), was normalerweise eine gute Sache ist, da Sie wahrscheinlich nach seiner Existenz suchen, um sie tatsächlich zu verwenden.
Als ein einfaches Beispiel, hier ist eine Funktion, die ausgeführt wird gdate
wenn es existiert, sonst date
:
gnudate() {
if hash gdate 2>/dev/null; then
gdate "$@"
else
date "$@"
fi
}
Das Folgende ist ein tragbarer Weg, um zu überprüfen, ob ein Befehl existiert $PATH
und ist ausführbar:
[ -x "$(command -v foo)" ]
Beispiel:
if ! [ -x "$(command -v git)" ]; then
echo 'Error: git is not installed.' >&2
exit 1
fi
Die ausführbare Überprüfung ist erforderlich, da bash eine nicht ausführbare Datei zurückgibt, wenn keine ausführbare Datei mit diesem Namen gefunden wird $PATH
.
Beachten Sie auch, dass eine nicht ausführbare Datei mit demselben Namen wie die ausführbare Datei früher existiert $PATH
, strich gibt ersteres zurück, obwohl letzteres ausgeführt werden würde. Dies ist ein Bug und verletzt den POSIX-Standard. [Fehlerbericht] [Standard]
Außerdem schlägt dies fehl, wenn der gesuchte Befehl als Alias definiert wurde.
Ich stimme mit Lunath überein, um den Gebrauch von which
und seine Lösung ist vollkommen gültig für BASH-Benutzer. Um jedoch tragbarer zu sein, command -v
soll stattdessen 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 zur Spezifikation: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
Hinweis: type
ist POSIX-konform, aber type -P
ist nicht.
Ich habe eine Funktion in meiner .bashrc definiert, die dies erleichtert.
command_exists () {
type "$1" &> /dev/null ;
}
Hier ist ein Beispiel, wie es benutzt wird (von meinem .bash_profile
.)
if command_exists mvim ; then
export VISUAL="mvim --nofork"
fi
Es hängt davon ab, ob Sie wissen wollen, ob es in einem der Verzeichnisse in der $PATH
Variable oder ob Sie die absolute Position wissen. Wenn du wissen willst, ob es in der $PATH
variabel, verwenden
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 Umleitung nach /dev/null/
im ersten Beispiel unterdrückt die Ausgabe der which
Programm.
Erweiternd auf @ lhunaths und @ GregVs Antworten, hier ist der Code für die Leute, die diesen Check einfach in ein if
Erklärung:
exists()
{
command -v "$1" >/dev/null 2>&1
}
So verwenden Sie es:
if exists bash; then
echo 'Bash exists!'
else
echo 'Your system does not have Bash'
fi
Versuchen Sie es mit:
test -x filename
oder
[ -x filename ]
Von der Bash-Manpage unter Bedingte Ausdrücke:
-x file True if file exists and is executable.
Benutzen hash
, wie @lhunath schlägt vor, in einem Bash-Skript:
hash foo &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "foo not found."
fi
Dieses Skript wird ausgeführt hash
und überprüft dann, ob der Beendigungscode des letzten Befehls der Wert ist, in dem gespeichert wird $?
, entspricht 1
. Ob hash
findet nicht foo
, wird der Exit-Code sein 1
. Ob foo
vorhanden ist, wird der Exit-Code sein 0
.
&> /dev/null
leitet Standardfehler und Standardausgabe von um hash
so dass es nicht auf dem Bildschirm erscheint und echo >&2
schreibt die Nachricht in den Standardfehler.
Ich habe nie die obigen Lösungen bekommen, um an der Box zu arbeiten, auf die ich Zugriff habe. Zum einen wurde Typ installiert (was mehr tut). Also wird die eingebaute Direktive benötigt. Dieser Befehl funktioniert für mich:
if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi