Wie teste ich, ob eine Anwendung in $ PATH vorhanden ist?

19

Ich versuche, alle meine shStartup / Env-Skripte so zu schreiben , dass sie mit so viel DRY und so viel wie möglich funktionieren: "Funktioniert auf jedem * nix, auf das ich es klone". Dies bedeutet, dass der Code ordnungsgemäß fehlschlägt, wenn ich versuche, Code auszuführen, der nicht vorhanden ist. Zu diesem Zweck muss ich testen können, ob Programme vorhanden sind. Ich weiß, wie man prüft, ob eine Datei vorhanden ist, aber ich bin nicht sicher, wie man prüft, ob eine Anwendung im Pfad ausführbar ist. Ich würde lieber den $ PATH verwenden, da einige von diesen auf Arch, Ubuntu und Centos arbeiten müssen. Einige werden möglicherweise in meinem Homedir auf Systemen installiert, auf denen ich kein Root-Verzeichnis habe, andere werden möglicherweise nicht installiert, und andere werden möglicherweise in Systempfaden installiert.

Xenoterracid
quelle
2
Diese SO-Antwort ist die, die ich für solche Fragen vorgemerkt habe.
JW013

Antworten:

19

Verwenden Sie type commandname. Dies gibt true zurück, wenn commandnameetwas ausführbar ist: Alias, Funktion, eingebauter oder externer Befehl (nachgeschlagen in $PATH). Alternativ können Sie auch command commandnameden Wert true verwenden, wenn commandnamees sich um einen eingebauten oder einen externen Befehl handelt (der nachgeschlagen wurde $PATH).

exists () {
  type "$1" >/dev/null 2>/dev/null
}

Es gibt einige sh-Varianten (definitiv vor POSIX; ich kenne /bin/shOSF1 ≤3.x und einige Versionen der Almquist-Shell, die in früheren NetBSD-Versionen und einigen Linux-Distributionen des 20. Jahrhunderts enthalten waren), bei denen typeimmer 0 zurückgegeben wird oder nicht existieren. Ich glaube nicht, dass in diesem Jahrtausend Systeme mit diesen ausgeliefert wurden. Wenn Sie jemals auf sie stoßen, können Sie mit der folgenden Funktion $PATHmanuell suchen :

exists () { (
    IFS=:
    for d in $PATH; do
      if test -x "$d/$1"; then return 0; fi
    done
    return 1
) }

Diese Funktion ist im Allgemeinen nützlich, wenn Sie integrierte Funktionen ausschließen und den Namen in nachschlagen möchten $PATH. Die meisten Shells verfügen über eine integrierte Funktion command -v, obwohl es sich um eine relativ neue POSIX-Erweiterung handelt (ab POSIX: 2004 immer noch optional). Dies ist im Grunde eine programmiererfreundliche Version von type: Sie gibt den vollständigen Pfad für eine ausführbare Datei $PATH, den bloßen Namen für eine integrierte Funktion und eine Aliasdefinition für einen Alias ​​aus.

exists_in_path () {
  case $(command -v -- "$1") in
    /*) return 0;;
    alias\ *) return 1;; # alias
    *) return 1;; # built-in or function
  esac
}

Ksh, bash und zsh müssen auch type -pnur ausführbare Dateien in suchen $PATH. Beachten Sie, dass in bash der Rückgabestatus type -p foo0 ist, wenn fooes sich um eine integrierte Funktion handelt. Wenn Sie auf eine ausführbare Datei in testen möchten $PATH, müssen Sie sicherstellen, dass die Ausgabe nicht leer ist. type -pist nicht in POSIX; Zum Beispiel hat Debians Asche (die /bin/shauf Ubuntu ist) es nicht.

Gilles 'SO - hör auf böse zu sein'
quelle
@gilles, wird das (oder etwas ähnliches) if [ type keychain ]; thennicht funktionieren? Ich bekomme eine Fehlermeldung, /home/xenoterracide/.zshrc:84: parse error: condition expected: typeich nehme an, ich könnte schreiben, dass die Funktion existiert ... Ich dachte nur, dass dies in
gewissem
@xenoterracide: Lass die Klammern fallen!
Gilles 'SO- hör auf böse zu sein'
Ich denke, Sie suchen if type $APP >/dev/null 2>/dev/null; then ...Sie wollen das nicht [].
Steven D
4
Bah, ich wusste, ich hätte mich erfrischen sollen. Wieder geschlagen von Gilles!
Steven D
type -pwenn Sie speziell nach einem Befehl in suchen $PATH(keine Aliase oder Funktionen oder eingebauten).
Ephemient
1

Wenn Sie nur nach externen Programmen suchen, können Sie auch welche verwenden. Ich weiß allerdings nicht, wie portabel das ist.

Kim
quelle
3
Theoretisch ist es weniger portabel als typeoder command; whichist zum Beispiel nicht in POSIX. In der Praxis whichgibt es fast überall, aber an einigen Stellen (wo es als csh-Skript implementiert ist) wird ein anderer Pfad verwendet (aufgrund von a .cshrc), der den Zweck zunichte macht.
Gilles 'SO - hör auf böse zu sein'