Frage Wie überprüfe ich, ob ein Programm von einem Bash-Skript existiert?


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.


1573
2018-02-26 21:52


Ursprung


Antworten:


Antworten

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

Erläuterung

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?

  • Viele Betriebssysteme haben a 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).
  • Viele Betriebssysteme machen 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 hashDie 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). commandDer 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
}

2277
2018-03-24 12:45



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.


236
2017-11-05 14:33



Ich stimme mit Lunath überein, um den Gebrauch von whichund 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.


190
2018-01-24 18:16



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

81
2017-10-14 09:24



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.


66
2018-02-26 22:01



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

27
2017-12-07 21:17



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.

19
2018-02-26 21:57



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.


16
2018-06-24 17:01



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

7
2017-07-11 18:38