Wenn für den Pfad zu einem ausführbaren suchen oder prüfen , was passieren würde , wenn Sie einen Befehlsnamen in einem Unix - Shell geben, gibt es eine Fülle von verschiedenen Dienstprogramme ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
, etc.).
Wir hören oft, dass which
dies vermieden werden sollte. Warum? Was sollen wir stattdessen verwenden?
shell
history
which
portability
Stéphane Chazelas
quelle
quelle
which
gehen von einem interaktiven Shell-Kontext aus. Diese Frage ist markiert / Portabilität. Daher interpretiere ich die Frage in diesem Zusammenhang als "Was soll man verwenden, anstattwhich
die erste ausführbare Datei eines bestimmten Namens in der zu finden$PATH
". Die meisten Antworten und Gründe gegen denwhich
Umgang mit Aliasen, Builtins und Funktionen, die in den meisten realen portablen Shell-Skripten nur von akademischem Interesse sind. Lokal definierte Aliase werden beim Ausführen eines Shell-Skripts nicht vererbt (es sei denn, Sie geben sie als Quelle an.
).csh
(undwhich
istcsh
bei den meisten kommerziellen Unices immer noch ein Skript) liest,~/.cshrc
wenn es nicht interaktiv ist. Aus diesem Grund werden Sie feststellen, dass csh-Skripte normalerweise mit beginnen#! /bin/csh -f
.which
nicht , weil es zielt darauf ab , Ihnen die Aliasnamen zu geben, weil es als Werkzeug für die (interaktive) Nutzer gemeint istcsh
. POSIX-Shells haben Benutzercommand -v
.(t)csh
(oder es macht dir nichts aus, wenn sie dir nicht das richtige Ergebnis liefert), benutzetype
odercommand -v
stattdessen . Siehe die Antworten für warum .stat $(which ls)
ist aus mehreren Gründen falsch (fehlende--
, fehlende Anführungszeichen), nicht nur die Verwendung vonwhich
). Du würdest benutzenstat -- "$(command -v ls)"
.ls
Dies setzt voraus, dass es sich in der Tat um einen Befehl handelt, der im Dateisystem vorhanden ist (kein in Ihre Shell integrierter Befehl oder eine Aliasfunktion).which
Möglicherweise geben Sie den falschen Pfad an (nicht den Pfad, den Ihre Shell ausführen würde, wenn Sie eingebenls
) oder geben Ihnen einen Alias, wie in der Konfiguration einiger anderer Shells definiert ...which
Implementierungen nicht einmal das liefernls
würden, was durch ein Nachschlagen von gefunden werden würde$PATH
(unabhängig davon, wasls
in Ihrer Shell aufgerufen werden könnte).sh -c 'command -v ls'
oderzsh -c 'rpm -q --whatprovides =ls'
eher die richtige Antwort geben. Der Punkt hier ist, dasswhich
ein gebrochenes Erbe auscsh
.Antworten:
Hier ist alles, was Sie nie gedacht hätten, dass Sie jemals davon nichts wissen wollen:
Zusammenfassung
So rufen Sie den Pfadnamen einer ausführbaren Datei in einem Bourne-ähnlichen Shell-Skript ab (es gibt einige Vorsichtsmaßnahmen; siehe unten):
So stellen Sie fest, ob ein bestimmter Befehl vorhanden ist:
An der Eingabeaufforderung einer interaktiven Bourne-ähnlichen Shell:
Der
which
Befehl ist ein zerbrochenes Erbe der C-Shell und sollte besser in Bourne-ähnlichen Shells allein gelassen werden.Anwendungsfälle
Es gibt einen Unterschied, ob Sie diese Informationen als Teil eines Skripts oder interaktiv an der Shell-Eingabeaufforderung suchen.
An der Shell-Eingabeaufforderung lautet der typische Anwendungsfall: Dieser Befehl verhält sich merkwürdig. Verwende ich den richtigen? Was genau ist passiert, als ich getippt habe
mycmd
? Kann ich mir genauer ansehen, was es ist?In diesem Fall möchten Sie wissen, was Ihre Shell tut, wenn Sie den Befehl aufrufen, ohne ihn tatsächlich aufzurufen.
In Shell-Skripten sieht es meistens ganz anders aus. In einem Shell-Skript gibt es keinen Grund, warum Sie wissen möchten, wo oder was ein Befehl ist, wenn Sie ihn nur ausführen möchten. Im Allgemeinen möchten Sie den Pfad der ausführbaren Datei kennen, damit Sie mehr Informationen daraus abrufen können (z. B. den Pfad zu einer anderen Datei im Verhältnis dazu oder Informationen aus dem Inhalt der ausführbaren Datei unter diesem Pfad lesen).
Interaktiv, können Sie darüber wissen alle die
my-cmd
Befehle auf dem System, in Skripten, selten so.Die meisten verfügbaren Tools wurden (wie so oft) für die interaktive Verwendung entwickelt.
Geschichte
Ein bisschen Geschichte zuerst.
Die frühen Unix-Shells hatten bis Ende der 70er Jahre keine Funktionen oder Aliase. Nur das traditionelle Nachschlagen von ausführbaren Dateien in
$PATH
.csh
eingeführt Aliase um 1978 (obwohlcsh
wurde zuerst veröffentlicht in2BSD
, der im Mai 1979), und auch die Verarbeitung einer.cshrc
für die Benutzer die Schale gestalten (jede Schale, wiecsh
liest.cshrc
auch wenn sie nicht interaktiv wie in Skripten).Während die Bourne-Shell 1979 zum ersten Mal in Unix V7 veröffentlicht wurde, wurde die Funktionsunterstützung erst viel später hinzugefügt (1984 in SVR2), und es gab sowieso nie eine
rc
Datei (die.profile
dient zum Konfigurieren Ihrer Umgebung, nicht die Shell an sich ).csh
wurde viel populärer als die Bourne-Shell, da sie (obwohl sie eine schrecklich schlechtere Syntax als die Bourne-Shell hatte) viele bequemere und schönere Funktionen für den interaktiven Gebrauch hinzufügte.In
3BSD
(1980), einwhich
csh - Skript wurde für die hinzugefügtencsh
Benutzer eine ausführbare Datei zu identifizieren, und es ist ein kaum anderes Skript Sie findenwhich
auf vielen kommerziellen Unix - Varianten heute (wie Solaris, HP / UX, AIX oder Tru64).Dieses Skript liest den Benutzer
~/.cshrc
(wie allecsh
Skripte, sofern sie nicht mit aufgerufen werdencsh -f
) und sucht die angegebenen Befehlsnamen in der Liste der Aliase und in$path
(dem Array,csh
das auf der Grundlage verwaltet wird$PATH
).Los geht's,
which
kam als erstes für die damals beliebteste Shell (undcsh
war bis Mitte der 90er Jahre immer noch beliebt), was der Hauptgrund ist, warum sie in Büchern dokumentiert wurde und immer noch weit verbreitet ist.Beachten Sie
csh
, dass dieseswhich
csh-Skript auch für einen Benutzer nicht unbedingt die richtigen Informationen enthält. Es werden die in definierten Aliase abgerufen~/.cshrc
, nicht die Aliase , die Sie möglicherweise später an der Eingabeaufforderung oder beispielsweise durch diesource
Eingabe einer anderencsh
Datei definiert haben, und (obwohl dies keine gute Idee wäre)PATH
möglicherweise in neu definiert~/.cshrc
.Wenn Sie diesen
which
Befehl über eine Bourne-Shell ausführen, werden die in Ihrer definierten Aliase weiterhin gesucht.~/.cshrc
Wenn Sie jedoch keinen haben, weil Sie ihn nicht verwendencsh
, erhalten Sie wahrscheinlich immer noch die richtige Antwort.Eine ähnliche Funktionalität wurde der Bourne-Shell erst 1984 in SVR2 mit dem
type
eingebauten Befehl hinzugefügt. Die Tatsache, dass es (im Gegensatz zu einem externen Skript) eingebaut ist, bedeutet, dass es Ihnen (in gewissem Umfang) die richtigen Informationen geben kann , da es Zugriff auf die Interna der Shell hat.Der ursprüngliche
type
Befehl hatte ein ähnliches Problem wie daswhich
Skript, da er keinen Fehlerbeendigungsstatus zurückgab, wenn der Befehl nicht gefunden wurde. Im Gegensatz dazu wird für ausführbare Dateien nicht nur daswhich
ausgegeben, was die Verwendung in Skripten erschwert.ls is /bin/ls
/bin/ls
Die Bourne-Shell von Unix Version 8 (nicht im
type
Umlauf) wurde umbenanntwhatis
. Und die Plan9-Shellrc
( der ehemalige Nachfolger von Unix) (und ihre Derivate wieakanga
undes
) haben eswhatis
ebenfalls.Die Korn-Shell (eine Teilmenge, auf der die POSIX-sh-Definition basiert), die Mitte der 80er Jahre entwickelt wurde, aber vor 1988 nicht allgemein verfügbar war, fügte viele der
csh
Funktionen (Zeileneditor, Aliase ...) der Bourne-Shell hinzu . Es wurdewhence
(zusätzlich zutype
) ein eigenes eingebautes Programm hinzugefügt , das mehrere Optionen-v
zur Verfügung stellte ( um dietype
ähnlich ausführliche Ausgabe bereitzustellen und-p
nur nach ausführbaren Dateien zu suchen (keine Aliase / Funktionen ...)).In den späten 80er Jahren, Anfang der 90er Jahre, kamen einige freie Software- Shell-Implementierungen heraus , die mit den Turbulenzen in Bezug auf die Urheberrechtsprobleme zwischen AT & T und Berkeley einhergingen. Die gesamte Almquist-Shell (ash, die die Bourne-Shell in BSDs ersetzen soll), die gemeinfreie Implementierung von ksh (pdksh)
bash
(gesponsert von der FSF),zsh
wurde zwischen 1989 und 1991 veröffentlicht.Obwohl Ash als Ersatz für die Bourne-Shell
type
gedacht war, wurde es erst viel später (in NetBSD 1.3 und FreeBSD 2.3) eingebauthash -v
. OSF / 1/bin/sh
hatte einetype
eingebaute Version, die immer 0 bis OSF / 1 v3.x zurückgab.bash
fügte kein hinzuwhence
, fügte aber eine-p
Option hinzutype
, um den Pfad auszudrucken (type -p
würde lautenwhence -p
) und alle übereinstimmenden Befehle-a
zu melden . made builtin und fügte einen Befehl hinzu , der sich wie 's verhält . hat sie alle.tcsh
which
where
bash
type -a
zsh
In der
fish
Shell (2005) ist eintype
Befehl als Funktion implementiert.Das
which
csh-Skript wurde in der Zwischenzeit aus NetBSD entfernt (da es in tcsh eingebaut und in anderen Shells nicht sehr nützlich ist) und die Funktionalität wurde hinzugefügtwhereis
(wenn es als aufgerufen wirdwhich
,whereis
verhält es sich so,which
dass es nur ausführbare Dateien in sucht$PATH
). In OpenBSD und FreeBSDwhich
wurde auch eine in C geschriebene geändert, die$PATH
nur Befehle in sucht .Implementierungen
Es gibt Dutzende von Implementierungen eines
which
Befehls auf verschiedenen Unices mit unterschiedlicher Syntax und unterschiedlichem Verhalten.Unter Linux (neben den in
tcsh
und eingebautenzsh
) gibt es mehrere Implementierungen. Auf neueren Debian-Systemen ist es beispielsweise ein einfaches POSIX-Shell-Skript, das nach Befehlen in sucht$PATH
.busybox
hat auch einenwhich
Befehl.Es gibt eine,
GNU
which
die wahrscheinlich die extravaganteste ist. Es versucht, das, was daswhich
csh-Skript getan hat, auf andere Shells auszudehnen : Sie können sagen, was Ihre Aliase und Funktionen sind, damit Sie eine bessere Antwort erhalten (und ich glaube, dass einige Linux-Distributionen einige globale Aliase setzen, um diesbash
zu tun). .zsh
Es gibt einige Operatoren , die auf den Pfad der ausführbaren Dateien erweitert werden müssen: den=
Dateinamenerweiterungsoperator und den:c
Änderungswert für die Verlaufserweiterung (hier angewendet auf die Parametererweiterung ):zsh
zsh/parameters
macht im Modul auch die Kommando-Hash-Tabelle zumcommands
assoziativen Array:Das
whatis
Hilfsprogramm (mit Ausnahme des Hilfsprogramms in der Unix V8 Bourne-Shell oder Plan 9rc
/es
) ist nicht wirklich verwandt, da es nur zur Dokumentation dient (greift auf die whatis-Datenbank zu, dh auf die Manpage-Übersicht).whereis
Wurde auch3BSD
zur gleichen Zeit hinzugefügt, alswhich
wäre es in geschriebenC
, nichtcsh
und wird verwendet, um zur gleichen Zeit die ausführbare Datei, die Manpage und den Quellcode zu suchen, aber nicht basierend auf der aktuellen Umgebung. Das entspricht einem anderen Bedürfnis.An der Standardfront gibt POSIX nun die Befehle
command -v
und an-V
(die bis POSIX.2008 optional waren). UNIX gibt dentype
Befehl an (keine Option). Das ist alles (where
,which
,whence
sind in keiner Norm festgelegt)Bis zu einer bestimmten Version
type
undcommand -v
optional in der Linux Standard Base-Spezifikation, was erklärt, warum zum Beispiel einige alte Versionen vonposh
(obwohl aufpdksh
denen beide basierten ) keine hatten.command -v
wurde auch zu einigen Bourne-Shell-Implementierungen hinzugefügt (wie unter Solaris).Status Heute
Heutzutage ist dies der Status
type
und ercommand -v
ist in allen Bourne-ähnlichen Shells allgegenwärtig (beachten Sie jedoch, wie von @jarno bemerkt, die Einschränkung / den Fehler,bash
wenn Sie sich nicht im POSIX-Modus befinden, oder einige Nachkommen der Almquist-Shell, die in den Kommentaren unten aufgeführt sind).tcsh
ist die einzige Shell, die Sie verwenden möchtenwhich
(da keinetype
vorhanden undwhich
eingebaut ist).In den Schalen ausgenommen
tcsh
undzsh
,which
man kann sagen , den Pfad der gegebenen ausführbaren solange es keine Alias oder eine Funktion von demselben Namen in einem unserer~/.cshrc
,~/.bashrc
oder jede Shell - Startdatei und Sie definieren nicht$PATH
in Ihrem~/.cshrc
. Wenn Sie einen Alias oder eine Funktion dafür definiert haben, kann er oder sie Ihnen davon erzählen, oder sie können Ihnen das Falsche sagen.Wenn Sie über alle Befehle unter einem bestimmten Namen informiert werden möchten, gibt es nichts Tragbares. Sie würden
where
intcsh
oderzsh
,type -a
inbash
oderzsh
,whence -a
in ksh93 und in anderen Shells verwenden, die Sietype
in Kombination mitwhich -a
denen verwenden können, die möglicherweise funktionieren.Empfehlungen
Abrufen des Pfadnamens zu einer ausführbaren Datei
Um den Pfadnamen einer ausführbaren Datei in einem Skript zu ermitteln, gibt es einige Vorsichtsmaßnahmen:
wäre der Standard Weg, um es zu tun.
Es gibt jedoch einige Probleme:
type
,which
,command -v
... alle Heuristik verwendet den Weg , um herauszufinden. Sie durchlaufen die$PATH
Komponenten und suchen die erste Nicht-Verzeichnis-Datei, für die Sie die Berechtigung zum Ausführen haben. Abhängig von der Shell führen viele von ihnen (Bourne, AT & T ksh, zsh, ash ...) die Ausführung in der Reihenfolge aus,$PATH
bis derexecve
Systemaufruf nicht mehr mit einem Fehler zurückkehrt . Zum Beispiel, wenn$PATH
enthält/foo:/bar
und Sie ausführen möchtenls
, werden sie zuerst versuchen, auszuführen,/foo/ls
oder wenn dies fehlschlägt/bar/ls
. Jetzt Ausführung von/foo/ls
kann fehlschlagen, weil Sie keine Ausführungsberechtigung haben, aber auch aus vielen anderen Gründen, zum Beispiel, weil es keine gültige ausführbare Datei ist.command -v ls
würde melden,/foo/ls
ob Sie über die Ausführungsberechtigung für verfügen/foo/ls
, aberls
möglicherweise tatsächlich ausgeführt werden,/bar/ls
wenn/foo/ls
keine gültige ausführbare Datei vorhanden ist.foo
es sich um eine integrierte Funktion oder einen Alias handelt, wirdcommand -v foo
zurückgegebenfoo
. Mit einigen Muscheln mögenash
,pdksh
oderzsh
kann es auch zurückkehren ,foo
wenn$PATH
die leere Zeichenfolge enthält und es gibt eine ausführbarefoo
Datei im aktuellen Verzeichnis. Unter bestimmten Umständen müssen Sie dies möglicherweise berücksichtigen. Denken Sie zum Beispiel daran, dass die Liste der integrierten Funktionen von der Shell-Implementierung abhängt (zum Beispielmount
wird sie manchmal für busybox integriertsh
) undbash
Funktionen aus der Umgebung abrufen kann.$PATH
relative Pfadkomponenten enthalten sind (normalerweise.
oder die leere Zeichenfolge, die sich beide auf das aktuelle Verzeichnis beziehen, aber allescommand -v cmd
Mögliche sein können), wird je nach Shell möglicherweise kein absoluter Pfad ausgegeben. Daher ist der Pfad, den Sie zum Zeitpunkt Ihres Laufs erhaltencommand -v
, nicht mehr gültig, nachdem Sie sich an einemcd
anderen Ort befinden./opt/ast/bin
(obwohl das genaue Pfad auf verschiedenen Systemen unterschiedlich sein kann glaube ich) in dir ist$PATH
, wird ksh93 zur Verfügung , ein paar zusätzliche builtins machen (chmod
,cmp
,cat
...), abercommand -v chmod
wird zurückkehren ,/opt/ast/bin/chmod
auch wenn dieser Weg doesn‘ existiert nicht.Bestimmen, ob ein Befehl vorhanden ist
Um herauszufinden, ob ein bestimmter Befehl standardmäßig vorhanden ist, können Sie Folgendes tun:
Wo könnte man verwenden wollen
which
(t)csh
In
csh
undtcsh
hast du nicht viel Auswahl. Intcsh
, das ist in Ordnung, wiewhich
es eingebaut ist. Diescsh
ist der Systembefehlwhich
, der in einigen Fällen möglicherweise nicht die gewünschten Aktionen ausführt.finde Befehle nur in einigen Shells
Ein Fall , in dem es könnte sinnvoll nutzen machen
which
, wenn Sie den Pfad einen Befehl wissen wollen, in potenziell Shell builtins oder Funktionen zu ignorierenbash
,csh
(nichttcsh
),dash
oderBourne
Shell - Scripts, also Schalen, die nicht überwhence -p
(wieksh
oderzsh
) ,command -ev
(likeyash
),whatis -p
(rc
,akanga
) oder ein eingebauteswhich
(liketcsh
oderzsh
) auf Systemen, wowhich
verfügbar ist und nicht dascsh
Skript.Wenn diese Bedingungen erfüllt sind, dann:
würde dir den Pfad des Ersten
echo
in$PATH
(außer inecho
Eckfällen ) geben, unabhängig davon, ob es sich auch um eine eingebaute / alias / Funktion handelt oder nicht.In anderen Shells bevorzugen Sie:
echo==echo
oderecho=$commands[echo]
oderecho=${${:-echo}:c}
echo=$(whence -p echo)
echo=$(command -ev echo)
echo=`whatis -p echo`
(Vorsicht vor Pfaden mit Leerzeichen)set echo (type -fp echo)
Beachten Sie, dass Sie, wenn Sie nur diesen
echo
Befehl ausführen möchten , den Pfad nicht abrufen müssen, sondern einfach Folgendes tun können:Zum Beispiel mit
tcsh
, um zu verhindern, dass das eingebaute Elementwhich
verwendet wird:wenn Sie einen externen Befehl benötigen
Ein weiterer Fall, den Sie möglicherweise verwenden möchten,
which
ist, wenn Sie tatsächlich einen externen Befehl benötigen . POSIX setzt voraus, dass alle Shell-Builtins (wiecommand
) auch als externe Befehle verfügbar sind, wascommand
auf vielen Systemen leider nicht der Fall ist. Beispielsweise ist es selten,command
unter Linux-basierten Betriebssystemen einen Befehl zu finden , während die meisten von ihnen einenwhich
Befehl haben (wenn auch verschiedene mit unterschiedlichen Optionen und Verhaltensweisen).Fälle, in denen Sie einen externen Befehl benötigen, sind alle Fälle, in denen Sie einen Befehl ausführen, ohne eine POSIX-Shell aufzurufen.
Die
system("some command line")
,popen()
... -Funktionen von C oder verschiedenen Sprachen rufen eine Shell auf, um diese Befehlszeile zu analysieren.system("command -v my-cmd")
Arbeiten Sie also mit ihnen. Eine Ausnahme wäre,perl
die die Shell optimiert, wenn sie kein Shell-Sonderzeichen (außer Leerzeichen) sieht. Das gilt auch für seinen Backtick-Betreiber:Die Hinzufügung des
:;
obenperl
Gesagten zwingt dazu, dort eine Shell aufzurufen. Wenn Sie verwendenwhich
, müssten Sie diesen Trick nicht anwenden.quelle
which
ist eincsh
Skript für viele kommerzielle Unices. Der Grund ist historisch, deshalb habe ich die Geschichte angegeben, damit die Leute verstehen, woher sie stammt, warum die Leute sich daran gewöhnt haben und warum es eigentlich keinen Grund gibt, warum Sie sie verwenden sollten. Und ja, manche Leute benutzen (t) csh. Noch verwendet nicht jeder Linuxwhich
, wie die Dinge im Gegensatz Sie verwenden könnten versuchen ,which
zu tun, die Geschichtewhich
, Implementierungenwhich
, anderer Befehle bezogene Aufgaben zu tun, oder Gründe tatsächlich zu nutzenwhich
? Warum sind die anderen Befehle besser ? Was machen sie anders alswhich
? Wie vermeiden sie seine Fallstricke? Diese Antwort gibt tatsächlich mehr Worte über die Probleme mit den Alternativen aus als über die Probleme mitwhich
.command -v
wird die Ausführungsberechtigung nicht überprüft, zumindest wenn Sie sie mit einem reinen Dateinamenargument ohne Pfad aufrufen. Ich habe mit Dash 0.5.8 und GNU Bash 4.3.48 getestet.touch /usr/bin/mytestfile
und danach startecommand -v mytestfile
, wird der Pfad angegeben (wohingegenwhich mytestfile
dies nicht der Fall ist).bash
wird sich für eine nicht ausführbare Datei entscheiden, wenn sie keine ausführbare Datei finden kann, also ist es "OK" (obwohl in der Praxis eher eincommand -v
/type
Fehler zurückgegeben wird), da dies der Befehl ist, den sie ausführen würde, wenn Sie ausführenmytestfile
, aber diedash
Verhalten ist fehlerhaft, als ob es eine nicht ausführbare Dateicmd
vor einer ausführbaren gibt,command -v
gibt die nicht ausführbare Datei zurück, währendcmd
die ausführbare Datei ausgeführt wird (die falsche Datei ist ebenfalls gehasht). FreeBSDsh
(auch basierend aufash
) hat den gleichen Fehler. zsh, yash, ksh, mksh, bash wie sh sind OK.Die Gründe, warum man nicht verwenden möchte,
which
wurden bereits erläutert, aber hier sind einige Beispiele für einige Systeme, bei denenwhich
tatsächlich ein Fehler auftritt.Bei Bourne-ähnlichen Shells wird die Ausgabe von
which
mit der Ausgabe von verglichentype
(datype
es sich um eine eingebaute Shell handelt, handelt es sich um die grundlegende Wahrheit, da sie uns sagt, wie ein Befehl aufgerufen werden würde).Viele Fälle sind Ecke Fälle, aber bedenken Sie, dass
which
/type
häufig in der Ecke Fällen verwendet werden (um die Antwort auf ein unerwartetes Verhalten zu finden wie: ? Warum auf der Erde ist , dass Befehl so zu verhalten, die eine bin ich Aufruf ).Die meisten Systeme, die meisten Bourne-ähnlichen Shells: Funktionen
Der naheliegendste Fall betrifft Funktionen:
Der Grund dafür ist, dass
which
nur Berichte über ausführbare Dateien und manchmal über Aliase (obwohl nicht immer die Ihrer Shell) erstellt werden und nicht über Funktionen.Die GNU welche Manpage hat ein kaputtes (da sie vergessen haben zu zitieren
$@
) Beispiel, wie man es benutzt, um auch Funktionen zu melden, aber genau wie bei Aliases, weil es keinen Shell Syntax Parser implementiert, ist es leicht zu täuschen:Die meisten Systeme, die meisten Bourne-ähnlichen Shells: Builtins
Ein weiterer offensichtlicher Fall ist builtins oder Keywords, als
which
sein ein externer Befehl hat keine Möglichkeit zu wissen , welche builtins Shell (und einige Granaten wiezsh
,bash
oderksh
kann builtins dynamisch laden):(das gilt nicht für
zsh
wowhich
wird builtin)Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5.1 und viele andere:
Das liegt daran, dass auf den meisten kommerziellen Unices
which
(wie in der ursprünglichen Implementierung auf 3BSD) eincsh
Skript zum Lesen vorhanden ist~/.cshrc
. Die Aliasnamen, die gemeldet werden, sind diejenigen, die dort definiert sind, unabhängig von den aktuell von Ihnen definierten Aliasnamen und unabhängig von der Shell, die Sie tatsächlich verwenden.In HP / UX oder Tru64:
(Die Solaris- und AIX-Versionen haben dieses Problem behoben, indem sie es
$path
vor dem Lesen~/.cshrc
gespeichert und wiederhergestellt haben, bevor die Befehle aufgerufen wurden.)Oder:
(Natürlich
csh
können Sie nicht erwarten , dass ein Skript mit Argumenten arbeitet, die Leerzeichen enthalten ...)CentOS 6.4, bash
Auf diesem System gibt es einen systemweit definierten Alias, der den GNU-
which
Befehl umschließt .Die gefälschte Ausgabe ist da
which
die Ausgabe liestbash
‚salias
aber nicht weiß , wie man es richtig zu analysieren und verwendet Heuristiken (ein Alias pro Zeile, sucht der erste Befehl nach einer gefunden|
,;
,&
...)Das Schlimmste an CentOS ist, dass
zsh
es einen perfektwhich
eingebauten Befehl gibt, aber CentOS hat es geschafft, ihn zu brechen, indem es durch einen nicht funktionierenden Alias für GNU ersetzt wurdewhich
.Debian 7.0, ksh93:
(gilt jedoch für die meisten Systeme mit vielen Shells)
Auf Debian
/bin/which
ist ein/bin/sh
Skript. In meinem Fallsh
ist ,dash
aber es ist das gleiche , wenn esbash
.Ein ungesetzt
PATH
ist nicht zu deaktivierenPATH
Lookup, bedeutet aber das System unter Verwendung von Standard - PATH , die leider auf Debian, niemand stimmt (dash
undbash
habe/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
,zsh
hat/bin:/usr/bin:/usr/ucb:/usr/local/bin
,ksh93
hat/bin:/usr/bin
,mksh
hat/usr/bin:/bin
($(getconf PATH)
),execvp()
(wie inenv
) hat:/bin:/usr/bin
(ja, sieht im aktuellen Verzeichnis zuerst! )).Welches ist , warum
which
es falsch oben bekommt , da es mitdash
‚s Standard ,PATH
die aus unterschiedlichen istksh93
‘ sEs ist nicht besser mit GNU,
which
das berichtet:(Interessanterweise gibt es
/usr/local/bin/which
auf meinem System tatsächlich einakanga
Skript, das mitgeliefert wurdeakanga
(einrc
Shell-Derivat, in dem die StandardeinstellungPATH
lautet/usr/ucb:/usr/bin:/bin:.
).Bash, jedes System:
Derjenige, auf den sich Chris in seiner Antwort bezieht :
Auch nach
hash
manuellem Aufruf :Nun ein Fall, wo
which
und manchmaltype
scheitern:Nun mit einigen Muscheln:
Mit anderen:
Weder können
which
nochtype
können im Voraus wissen, dassb/foo
nicht ausgeführt werden kann. Einige Granaten wiebash
,ksh
oderyash
, wenn Aufruffoo
wird in der Tat versuchen zu laufenb/foo
einen Fehler und zu berichten, während andere (wiezsh
,ash
,csh
,Bourne
,tcsh
) läufta/foo
auf den Ausfall desexecve()
Systemaufruf aufb/foo
.quelle
mksh
verwendet tatsächlich etwas anderes für den Standard$PATH
: Zuerst wird die Kompilierungszeitkonstante des Betriebssystems_PATH_DEFPATH
verwendet (am häufigsten auf BSDs), dannconfstr(_CS_PATH, …)
wird POSIX verwendet, und wenn beide nicht vorhanden sind oder fehlschlagen,/bin:/usr/bin:/sbin:/usr/sbin
wird verwendet.ls
es sich um eine Funktion handelt, diesels
von PATH verwendet. Undwhich
ist gut zu sagen, welche verwendet wird/usr/bin/ls
oder/usr/local/bin/ls
. Ich sehe nicht "Warum nicht welche verwenden" ....which ls
wird mir geben ,/bin/ls
unabhängig davon , ob diels
Funktion aufruft/bin/ls
oder/opt/gnu/bin/ls
oderdir
oder gar nichts. IOW,which
(das, was Implementierungen, IMMV) gibt etwas irrelevantesls
eine Funktion ist. Ich weiß , dass meinels
Funktion ruftls
ausPATH
. Jetztwhich
sag mir wo die Datei ist. Es wird nur ein einziger Anwendungsfall angezeigt: "Was würde meine Shell mit diesem Befehl tun?" Für diesen Anwendungsfallwhich
ist falsch, richtig. Es gibt aber auch andere Anwendungsfälle, bei denen (GNU)which
genau das Richtige ist.which
Implementierung ab. Einige werden Ihnen sagen, dass es sich um einen Alias handelt (wenn Sie einen Alias konfiguriert haben oder wenn~/.cshrc
in Ihrem Heim ein solcher Alias vorhanden ist), andere geben Ihnen einen Pfad an, der unter bestimmten Bedingungen jedoch falsch ist.sh -c 'command -v ls'
Wenn auch nicht perfekt, ist es dennoch wahrscheinlicher, dass Sie die richtige Antwort auf diese unterschiedliche Anforderung erhalten (und dies ist auch Standard).Eine Sache, die Stephane (aus meiner kurzen Sicht) anscheinend nicht erwähnt hat, ist, dass
which
sie keine Ahnung von der Pfad-Hash-Tabelle Ihrer Shell hat. Dies hat zur Folge, dass möglicherweise ein Ergebnis zurückgegeben wird, das nicht für das tatsächlich ausgeführte Ergebnis repräsentativ ist, was das Debuggen unwirksam macht.quelle
Im Sinne von UNIX: Lassen Sie jedes Programm eine Sache gut machen.
Wenn das Ziel ist zu antworten: Welche ausführbare Datei existiert mit diesem Namen?
Das mit Debian-Systemen gelieferte ausführbare Programm ist eine gute Antwort. Das mit csh mitgelieferte Aliase, das ist eine Quelle von Problemen. Die, die einige Shells als internes Builtin bereitstellen, haben ein anderes Ziel. Verwenden Sie entweder diese ausführbare Datei oder das Skript am Ende dieser Antwort.
Wenn dieses Skript verwendet wird, ist die Antwort sauber, einfach und nützlich.
Dieses Ziel entspricht dem ersten Satz Ihrer Frage:
Wenn Sie ein System, das nicht ein ausführbares hat genannt , die ( die meisten Linux - Systeme haben) Sie eine in erstellen können ,
~/bin/which
bevor/bin/
in der PATH so persönlich ausführbar Übersteuerungssytem diejenigen wie am Ende der Post:Diese ausführbare Datei listet (standardmäßig) alle im PATH gefundenen ausführbaren Dateien auf. Wenn nur die erste erforderlich ist, ist die Option
-f
verfügbar.An diesem Punkt fallen wir in ein anderes Ziel:
Was die Shell ausführen wird (nach dem Parsen)
Das kommt aus deinem zweiten Satz:
Dieses zweite Thema versucht, eine gute Antwort auf eine Frage zu finden, die ziemlich schwer zu beantworten ist. Muscheln haben unterschiedliche Ansichten, Eckfälle und (zumindest) unterschiedliche Interpretationen. Hinzufügen dazu:
Und sicher, alle Versuche stimmen mit diesem Ziel überein.
Vermeiden Sie welche?
Ich frage mich: Warum sollte das gesagt werden, wenn es gut
which
funktioniert (zumindest in Debian)?Im Sinne von UNIX: Lassen Sie jedes Programm eine Sache gut machen.
Das externe Programm
which
macht eines: Suchen Sie die erste ausführbare Datei auf dem Pfad, die denselben Namen wie der Befehlsname hat . Und macht es einigermaßen gut.Ich kenne kein anderes Programm oder Dienstprogramm, das diese Frage grundlegender beantwortet. Als solches ist es nützlich und kann bei Bedarf verwendet werden.
Die
command -pv commandName
naheliegendste Alternative scheint zu sein :, aber das wird auch über eingebaute und Aliase berichten. Nicht die gleiche Antwort.Natürlich
which
ist es begrenzt, es beantwortet nicht alle Fragen, kein Tool könnte das tun (naja, noch nicht ...). Es ist jedoch nützlich, wenn Sie die Frage beantworten, für deren Beantwortung es entwickelt wurde (die Frage oben). Vieles davoned
wurde begrenzt undsed
erschien dann (odervi
/vim
). Oder wieawk
wurde begrenzt und ließ Perl erscheinen und erweitern. Dennoched
,sed
oder / undawk
spezifische Anwendungsfälle, wovim
oderperl
sind nicht die besten Werkzeuge.Wahrscheinlich, weil
which
ein Shell-Benutzer nur einen Teil der Frage beantwortet, die er möglicherweise stellt:Was wird ausgeführt, wenn ich einen Befehlsnamen eingebe?
Externe welche
Welche sollte (in vielen Systemen) als externe ausführbare Datei verfügbar sein.
Der einzige sichere Weg, dieses externe Tool aufzurufen, ist, env zu verwenden, um die Shell zu verlassen und dann aufzurufen
which
(was in allen Shells funktioniert):Oder verwenden Sie den vollständigen Pfad zu
which
(der auf verschiedenen Systemen variieren kann):Warum ist das
hack
nötig? Weil sich einige Muscheln (speziell zsh) versteckenwhich
:Ein externes Tool (wie
env
) zu sein, erklärt perfekt, warum es keine internen Shell-Informationen meldet. Wie Aliase, Funktionen, integrierte Funktionen, spezielle integrierte Funktionen, Shell-Variablen (nicht exportiert) usw.:Die leere Ausgabe von
ll
(ein allgemeiner Alias fürll='ls -l'
) zeigt an, dassll
keine Beziehung zu einem ausführbaren Programm besteht, oder zumindest, dass keine ausführbare Dateill
im PATH angegeben ist. Die Verwendung vonll
sollte etwas anderes aufrufen, in diesem Fall einen Alias:type
undcommand
Die Befehle
type
undcommand -v
werden von POSIX angefordert. Es ist zu erwarten, dass sie in den meisten Shells funktionieren, mit Ausnahme von csh, tcsh, fish und rc.Beide Befehle könnten verwendet werden, um einen anderen Gesichtspunkt bereitzustellen, von dem aus der Befehl ausgeführt wird.
whence
,where
,whereis
,whatis
,hash
Dann gibt es
whence
,where
,whereis
,whatis
,hash
, und einige andere. Alle unterschiedlichen Antworten auf ähnliche Fragen. Alle arbeiten auf unterschiedliche Weise in verschiedenen Schalen. Wahrscheinlichwhence
ist das am häufigsten nachtype
. Die anderen sind spezielle Lösungen, die dieselbe Frage auf unterschiedliche Weise beantworten.Wahrscheinlich
which
zuerst wissen , ob es eine ausführbare Datei mit dem Namen des existiert command , danntype
undcommand
dann, wenn die command noch nicht gefunden worden:whence
,where
,whereis
,whatis
,hash
in dieser Reihenfolge.Shell-Skript zur Bereitstellung einer
which
ausführbaren Datei.quelle
Ich habe das noch nie gehört. Bitte nennen Sie konkrete Beispiele. Ich würde mich um deine Linux-Distribution und die installierten Softwarepakete kümmern, da
which
kommt das ja woher !SLES 11.4 x 86-64
in tcsh version 6.18.01:
In der Bash-Version 3.2-147:
which
ist Teil von util-linux, einem Standardpaket, das von der Linux Kernel Organization zur Verwendung als Teil des Linux-Betriebssystems vertrieben wird. Diese anderen Dateien werden ebenfalls bereitgestelltMein
util-linux
ist Version 2.19. Versionshinweise sind leicht auf v2.13 vom (28-Aug-2007) zurückzuführen. Nicht sicher, was der Sinn oder das Ziel davon war, es wurde sicherlich nicht in dieser langwierigen Sache beantwortet, die 331 Mal aufgewertet wurde.quelle
which -v
, ist dies GNU (das extravagante, das in der anderen Antwort erwähnt wurde und in keiner Weise spezifisch für Linux ist), nicht util-linux, für das AFAIK niemals einwhich
Hilfsprogramm enthielt . util-linux 2.19 ist aus dem Jahr 2011, GNU 2.19 ist aus dem Jahr 2008.