Linux / Befehl command: Befehle ausführen, während Aliase und Funktionen umgangen werden

command ist ein Shell-Builtin-Befehl, der das Suchen nach Shell-Funktionen überspringt und entweder einen Builtin-Befehl oder einen externen Befehl ausführt, der in PATH gefunden wird. Er wird hauptsächlich verwendet, um den ursprünglichen Befehl aufzurufen, wenn eine Wrapper-Funktion mit demselben Namen erstellt wird, oder um mit command -v zu überprüfen, ob die aktuelle Shell den Befehl finden kann.

In Bash werden -v und -V verwendet, um Informationen zur Befehlsauflösung zu prüfen, und -p verwendet den Standard-Suchpfad, in dem Standardprogramme gefunden werden können. Er hat eine andere Rolle als exec, env und builtin, daher sollte er je nach Zweck unterschieden werden.

Was ist der Befehl command?

Eine Shell-Funktion kann denselben Namen wie ein externes Kommando haben. In diesem Fall kann das direkte Aufrufen des Namens innerhalb der Funktion dazu führen, dass die Funktion sich selbst erneut aufruft, was zu Rekursion führt. Wenn man ihn mit command voranstellt, wird die Shell-Funktion mit demselben Namen übersprungen und das Bash-Builtin-Kommando oder die ausführbare Datei ausgewählt, die in PATH gefunden wird.

command selbst ist eine eingebauter Befehl, der von Bash und mehreren anderen Shells bereitgestellt wird. Sie ist auch in POSIX definiert, aber detaillierte Ausgaben und erweitertes Verhalten können je nach Shell variieren.

Grundlegende Syntax

command [-pVv] command [arguments...]

Wenn sie ohne Optionen verwendet wird, führt sie das angegebene Kommando aus.

command ls -la
command printf '%s\n' 'hello'

In den meisten Situationen sieht es so aus, als ob das Kommando direkt ausgeführt wurde. Der Unterschied wird deutlich, wenn es eine Shell-Funktion mit demselben Namen gibt.

Aufrufen des ursprünglichen Befehls innerhalb einer Shell-Funktion

Die folgende Funktion gibt eine Nachricht aus, bevor sie ls ausführt, und ruft dann das ursprüngliche ls auf.

ls() {
 printf '%s\n' 'Prints the list.'
 command ls --color=auto "$@"
}

Das Schreiben von ls "$@" innerhalb der Funktion ruft dieselbe Funktion erneut auf. command ls umgeht die Funktionssuche, sodass ein eingebauter Bash-Befehl oder ein externer ls im PATH ausgeführt wird.

"$@" übergibt die an die Funktion übergebenen Argumente, während die ursprünglichen Grenzen beibehalten werden. Das Ersetzen durch $* oder ungequotetes $@ kann Argumente, die Leerzeichen oder Wildcards enthalten, beschädigen.

Überprüfen, ob ein Befehl mit command -v existiert

-v gibt eine kurze Form dessen aus, wie der angegebene Name in der aktuellen Shell interpretiert wird. Es gibt einen Erfolgsstatus zurück, wenn der Befehl gefunden wird, und einen Fehlerstatus, wenn nicht, was es nützlich macht, um die Existenz in Skripten zu überprüfen.

command -v git
command -v cd
command -v printf

Die Ausgabe kann nicht nur den ausführbaren Pfad beschreiben, sondern auch eingebaute Befehle, Funktionen oder Aliase. Daher sollte das Ergebnis nicht in allen Fällen als Dateipfad angesehen werden.

if command -v curl >/dev/null 2>&1; then
 printf '%s\n' 'curl is available.'
else
 printf '%s\n' 'Could not find curl.' >&2
fi

Überprüfen Sie detaillierte Informationen mit dem Befehl -V

-V druckt eine für Menschen besser lesbare detaillierte Beschreibung als -v.

command -V ls
command -V cd
command -V deploy

In der Automation können die Satzformate je nach Shell und Gebietsschema variieren, daher wird empfohlen, die Ausgabe von -V nicht zu parsen. Um die Existenz eines Skripts zu prüfen, verwenden Sie den Exit-Status von command -v.

command -p und der Standard-Suchpfad

-p verwendet den von der Shell bereitgestellten Standardwert PATH, um Standarddienstprogramme zu finden. Es kann verwendet werden, wenn der vom Benutzer geänderte PATH unzuverlässig ist oder wenn Sie Standardbefehle finden müssen.

command -p getconf PATH
command -p ls

Der tatsächliche Wert des Standardpfads variiert je nach System. -p garantiert keinen bestimmten absoluten Pfad oder ein Programm von einem bestimmten Anbieter, daher sollten Sie in Skripten, in denen Sicherheit wichtig ist, die Ausführungsumgebung und Vertrauensgrenzen separat gestalten.

Zusammenfassung der Befehlsoptionen

Option Beschreibung
-v Gibt die aktuelle Interpretation der Shell knapp aus, ohne den Befehl auszuführen.
-V Druckt eine detaillierte Erklärung, wie der Befehl interpretiert wird.
-p Führt einen Befehl unter Verwendung des Standard-Suchpfads aus, wo Standarddienstprogramme gefunden werden können.

Vorsicht beim Umgehen von Aliassen

Die Alias-Erweiterung erfolgt in der Verarbeitungsstufe der Shell-Syntax vor der Befehlsausführung. In interaktivem Bash wird command ls normalerweise verwendet, um den tatsächlichen Befehl anstelle des ls-Alias auszuführen, aber es sollte nicht als universelles Quoting-Werkzeug betrachtet werden, das sowohl Alias-Definitionen als auch den Erweiterungskontext der Shell steuert.

Alle Kandidaten für den aktuellen Namen können zuerst mit type -a überprüft werden.

type -a ls
command -V ls

Wenn Sie den aktuellen Alias einfach nicht anwenden möchten, können Sie entweder den Namen mit einem Backslash eingeben oder den bestätigten absoluten Pfad ausführen.

\ls
/usr/bin/ls

Der absolute Pfad kann je nach Distribution und Systemstruktur variieren, daher sollte er vor dem Hardcodieren überprüft werden.

command, builtin, exec und env vergleichen

Befehl Hauptrollen
command name Überspringt die Suche nach Shell-Funktionen mit demselben Namen und führt einen eingebauten Befehl oder einen PATH-Befehl aus.
builtin name Führt explizit einen Bash-eigenen Befehl mit demselben Namen aus.
exec name Ersetzt den aktuellen Shell-Prozess durch ein neues Programm. Wenn erfolgreich, kehrt es nicht zur ursprünglichen Shell zurück.
env VAR=value name Führt einen externen Befehl in einer Umgebung mit angepassten Umgebungsvariablen aus.
type name Zeigt, wie die aktuelle Bash einen Namen interpretiert, ohne den Befehl auszuführen.

Zum Beispiel, wenn Sie sicherstellen wollen, dass der eingebaute Bash-Befehl mit demselben Namen innerhalb einer Funktion aufgerufen wird, könnte builtin klarer sein, und wenn Sie sowohl externe Programme als auch eingebaute Befehle zulassen wollen, ist command geeignet.

Prinzipien der Verwendung von command -v in Skripten

Ausgabe verwerfen und den Exit-Status überprüfen

if ! command -v rsync >/dev/null 2>&1; then
 printf '%s\n' 'rsync is required.' >&2
 exit 1
fi

Diese Methode hängt nicht vom Ausgabeformat ab. Um sogar Fehlermeldungen zu verbergen, müssen sowohl die Standardausgabe als auch der Standardfehler umgeleitet werden.

Zusätzliche Überprüfungen, ob eine reguläre ausführbare Datei erforderlich ist

Selbst wenn command -v erfolgreich ist, kann das Ergebnis ein Alias, eine Funktion oder ein eingebauter Befehl sein. Wenn eine externe ausführbare Datei erforderlich ist, überprüfen Sie zusätzlich, ob das Ergebnis ein Pfad und eine reguläre ausführbare Datei ist.

path=$(command -v mytool) || exit 1

if [ -f "$path" ] && [ -x "$path" ]; then
 printf 'Executable file: %s\n' "$path"
fi

Da relative Pfade oder spezielle Shell-Ausgaben zurückgegeben werden können, gestalten Sie die Bedingungen entsprechend dem vorgesehenen Zweck.

Verständnis von TOCTOU-Problemen

Wenn Sie überprüfen, ob ein Befehl existiert, und ihn dann später ausführen, können sich die PATH- oder Dateien in der Zwischenzeit ändern. Dies reicht für einfache Benutzerführung aus, aber in sicherheitssensiblen Umgebungen sollten Sie den Prüfergebnissen nicht allein vertrauen und kontrollierte Pfade und Berechtigungen verwenden.

Exit-Status

Im Ausführungsmodus wird der Status des ausgeführten Befehls weitergegeben. Ein nicht gefundener Befehl führt normalerweise zu Status 127; ein gefundener, aber nicht ausführbarer Befehl zu 126. Mit -v und -V zeigt der Status an, ob der Name gefunden wurde.

command false
printf 'status=%d\n' "$?"

command does-not-exist
printf 'status=%d\n' "$?"

Der Exit-Status folgt der Bedeutung des ausgeführten Befehls, daher bedeutet ein Wert ungleich 0 nicht, dass command selbst defekt ist.

Häufig gestellte Fragen

Führt command nur externe Befehle aus?

Nein. In Bash überspringt es Shell-Funktionen und führt dann integrierte Befehle oder externe Befehle aus, die im PATH gefunden werden. Um nur externe Dateien zu finden, müssen Sie den Pfad mit Tools wie type -P überprüfen.

Ist das Ergebnis von command -v immer ein absoluter Pfad?

Nein. Das Ergebnis kann von Aliasen, Funktionen, reservierten Wörtern, integrierten Befehlen oder ausführbaren Dateien stammen. Verwenden Sie den Exit-Status, um die Existenz eines command zu überprüfen.

Kann es in der Form sudo command… verwendet werden?

Da command ein Shell-Builtin ist, kann sudo möglicherweise nicht direkt wie ein separates ausführbares Programm ausgeführt werden. Normalerweise übergibt man das erforderliche externe command direkt an sudo, oder wenn Shell-Syntax erforderlich ist, muss man die Shell explizit ausführen, während man die Zitatsetzung und Sicherheitsimplikationen versteht.

Warum ist command -v besser als which?

command -v wird von der Shell bereitgestellt und spiegelt die command-Interpretation der aktuellen Shell wider. which ist oft ein externes Programm, und je nach Implementierung kann es Aliase oder Funktionen möglicherweise nicht korrekt behandeln.

Wie kann ich Funktionen ignorieren und nur eingebaute Befehle ausführen?

Verwenden Sie in Bash builtin name. command name kann nicht nur eingebaute Befehle, sondern auch externe Befehle in PATH ausführen.

Können dieselben Optionen in anderen Shells verwendet werden?

Die Kernoperationen von -p, -v und -V sind in POSIX definiert, aber die Ausgabemeldungen und erweiterten Funktionen können je nach Shell variieren. Für die Automatisierung geben Sie die Ziel-Shell an und prüfen Sie deren Dokumentation.

Zusammenfassung

command ist nützlich, um den ursprünglichen Befehl aufzurufen, der durch eine Shell-Funktion verborgen sein könnte, und zu prüfen, ob der Befehl in der aktuellen Shell gefunden werden kann. Verwenden Sie command name zum Ausführen, command -v name zum Überprüfen der Existenz und command -V name für eine menschenlesbare detaillierte Beschreibung.

Beim Prüfen aller Kandidaten und Typen eines Befehls verwenden Sie type -a zusammen. Andere grundlegende Befehle finden Sie in der Linux-Befehlsliste und Übersicht.

Verweisen Sie auf offizielle Dokumente