Wenn Sie nach dem Pfad zu einer ausführbaren Datei suchen oder prüfen, was passieren würde, wenn Sie einen Befehlsnamen in eine Unix-Shell eingeben, gibt es eine Vielzahl verschiedener Dienstprogramme ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
usw.)
Wir hören oft, dass which
vermieden werden sollte. Warum? Was sollten wir stattdessen verwenden?
Kommentare
- Ich denke, die meisten Argumente gegen die Verwendung von
which
gehen von einem interaktiven Shell-Kontext aus. Diese Frage ist mit Tags / Portabilität versehen Die Frage in diesem Zusammenhang lautet „, was anstelle vonwhich
verwendet werden soll, um die erste ausführbare Datei eines bestimmten Namens in der$PATH
„. Die meisten Antworten und Gründe dagegenwhich
befasst sich mit Aliasen, integrierten Funktionen und Funktionen, die in den meisten tragbaren Shell-Skripten der realen Welt nur von akademischem Interesse sind. Lokal definierte Aliase werden beim Ausführen eines Shell-Skripts nicht ‚ vererbt (es sei denn, Sie beziehen es mit.
). - @MattBianco, ja,
csh
(undwhich
ist in den meisten Werbespots immer noch eincsh
-Skript Unices) liest~/.cshrc
, wenn es nicht interaktiv ist. Aus diesem Grund ‚ werden Sie ‚ feststellen, dass csh-Skripte normalerweise mit#! /bin/csh -f
beginnen.which
funktioniert nicht, weil darauf abzielt, Ihnen die Aliase zu geben, da ‚ als Werkzeug für gedacht ist (interaktive) Benutzer voncsh
. Benutzer von POSIX-Shells habencommand -v
. - @rudimeier, dann lautet die Antwort immer, es sei denn, Ihre Shell lautet
(t)csh
(oder es macht Ihnen nichts aus, ‚, wenn es nicht ‚ nicht das richtige Ergebnis liefert), verwenden Sietype
odercommand -v
stattdessen . Siehe die Antworten für warum . - @rudimeier, (
stat $(which ls)
ist aus mehreren Gründen falsch (, fehlende Anführungszeichen), nicht nur die Verwendung vonwhich
). Sie ‚ würdenstat -- "$(command -v ls)"
verwenden. Dies setzt voraus, dassls
tatsächlich ein Befehl ist, der im Dateisystem gefunden wird (kein integrierter Bestandteil Ihrer Shell oder Funktion eines Alias).which
gibt Ihnen möglicherweise den falschen Pfad (nicht den Pfad, den Ihre Shell ausführen würde, wenn Siels
eingeben) oder gibt Ihnen einen definierten Alias In der Konfiguration einiger anderer Shells … - @rudimeier gibt es wieder eine Reihe von Bedingungen, unter denen viele
which
-Implementierungen Ihnen nicht einmal die geben würdenls
, das durch Nachschlagen von$PATH
gefunden würde (unabhängig davon, wasls
ist kann in Ihrer Shell aufrufen).sh -c 'command -v ls'
oderzsh -c 'rpm -q --whatprovides =ls'
geben Ihnen eher die richtige Antwort. Der Punkt hier ist, dasswhich
ein gebrochenes Erbe voncsh
ist.
Antwort
Hier ist alles, was Sie nie gedacht hätten, dass Sie jemals nichts darüber wissen wollen:
Zusammenfassung
Um das zu erhalten Pfadname einer ausführbaren Datei in einem Bourne-ähnlichen Shell-Skript (es gibt einige Einschränkungen; siehe unten):
ls=$(command -v ls)
So stellen Sie fest, ob ein bestimmter Befehl vorhanden ist:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Auf Eingabeaufforderung einer interaktiven Bourne-ähnlichen Shell:
type ls
Die Der Befehl which
ist ein zerbrochenes Erbe der C-Shell und wird in Bourne-ähnlichen Shells besser in Ruhe gelassen.
Anwendungsfälle
Dort „Eine Unterscheidung zwischen der Suche nach diesen Informationen als Teil eines Skripts oder interaktiv an der Shell-Eingabeaufforderung.
An der Shell-Eingabeaufforderung lautet der typische Anwendungsfall: Dieser Befehl verhält sich seltsam Was genau ist passiert, als ich 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 den Befehl tatsächlich aufzurufen.
In Shell-Skripten ist dies in der Regel ganz anders. 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 möchten Sie möglicherweise über alle my-cmd
-Befehle Bescheid wissen, die auf dem System in Skripten selten verfügbar sind.
Die meisten verfügbaren Tools (wie es häufig der Fall ist) wurden für die interaktive Verwendung entwickelt.
Verlauf
Zuerst ein wenig Verlauf.
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
führte um 1978 Aliase ein (obwohl csh
zum ersten Mal in 2BSD
, im Mai 1979) und auch die Verarbeitung eines .cshrc
, damit Benutzer die Shell anpassen können (jede Shell als csh
, liest .cshrc
, auch wenn es nicht wie in Skripten interaktiv ist.
Während die Bourne-Shell 1979 erstmals in Unix V7 veröffentlicht wurde, wurde die Funktionsunterstützung nur stark erweitert später (1984 in SVR2) hatte es sowieso nie eine rc
-Datei (die .profile
dient zum Konfigurieren Ihrer Umgebung, nicht der Shell per se ).
csh
wurde viel beliebter als die Bourne-Shell als (obwohl sie eine schrecklich schlechtere Syntax als die hatte Bourne-Shell) wurden viele bequemere und schönere Funktionen für die interaktive Verwendung hinzugefügt.
In 3BSD
(1980) wurde eine which
csh-Skript wurde für die Benutzer csh
hinzugefügt, um die Identifizierung einer ausführbaren Datei zu erleichtern. Es handelt sich um ein kaum anderes Skript, das Sie als auf vielen kommerziellen Unices heutzutage (wie Solaris, HP / UX, AIX oder Tru64).
Dieses Skript liest die ~/.cshrc
des Benutzers (wie alle csh
-Skripte, sofern sie nicht mit csh -f
aufgerufen werden) und sucht die angegebenen Befehlsnamen in der Liste der Aliase und in $path
(das Array, das csh
basierend auf $PATH
verwaltet).
Los gehts: which
war der erste für die damals beliebteste Shell (und csh
war bis Mitte des Jahres noch beliebt. 90er Jahre), was der Hauptgrund ist, warum es in Büchern dokumentiert wurde und immer noch weit verbreitet ist.
Beachten Sie, dass selbst für einen csh
Benutzer which
csh-Skript gibt Ihnen nicht unbedingt die richtigen Informationen. Es werden die in ~/.cshrc
definierten Aliase abgerufen, nicht diejenigen, die Sie möglicherweise später an der Eingabeaufforderung definiert haben, oder beispielsweise durch source
eines anderen csh
-Datei, und (obwohl dies keine gute Idee wäre) PATH
wird möglicherweise in ~/.cshrc
.
Wenn Sie den Befehl which
in einer Bourne-Shell ausführen, werden weiterhin Aliase gesucht, die in Ihrem ~/.cshrc
definiert sind Wenn Sie keine haben, weil Sie csh
nicht verwenden, erhalten Sie wahrscheinlich immer noch die richtige Antwort.
Eine ähnliche Funktionalität wurde nicht hinzugefügt die Bourne-Shell bis 1984 in SVR2 mit dem eingebauten Befehl type
. Die Tatsache, dass es eingebaut ist (im Gegensatz zu einem externen Skript), bedeutet, dass es Ihnen (bis zu einem gewissen Grad) die richtigen Informationen geben kann, da es Zugriff auf die Interna der Shell hat.
Der anfängliche Befehl type
hatte ein ähnliches Problem wie das Skript which
, da er keinen Fehler-Exit-Status zurückgab, wenn Der Befehl wurde nicht gefunden. Außerdem gab er für ausführbare Dateien im Gegensatz zu which
etwas wie ls is /bin/ls
statt nur , was die Verwendung in Skripten weniger einfach machte.
Die Bourne-Shell der Unix-Version 8 (nicht in freier Wildbahn veröffentlicht) hatte die type
wurde in whatis
umbenannt. Und die Plan9-Shell (der künftige Nachfolger von Unix) rc
(und seine Derivate wie akanga
und es
) haben ebenfalls whatis
.
Die Korn-Muschel (eine Teilmenge davon die Die POSIX sh
-Definition basiert auf), die Mitte der 80er Jahre entwickelt wurde, aber vor 1988 nicht allgemein verfügbar war, fügte viele der csh
-Funktionen hinzu ( Zeileneditor, Aliase …) über der Bourne-Shell. Es wurde eine eigene whence
eingebaute Version (zusätzlich zu type
) hinzugefügt, die mehrere Optionen (-v
um die type
-ähnliche ausführliche Ausgabe bereitzustellen, und -p
, um nur nach ausführbaren Dateien zu suchen (keine Aliase / Funktionen …))
Zufällig zu den Turbulenzen in Bezug auf die Urheberrechtsprobleme zwischen AT & T und Berkeley kamen einige freie Software Shell-Implementierungen in den späten 80ern, frühen 90ern.Die gesamte Almquist-Shell (ash
, um die Bourne-Shell in BSDs zu ersetzen), die gemeinfreie Implementierung von ksh
(pdksh
), bash
(gesponsert von der FSF), zsh
erschien zwischen 1989 und 1989 1991.
Ash, obwohl als Ersatz für die Bourne-Shell gedacht, hatte erst viel später (in NetBSD 1.3 und FreeBSD 2.3) eine type
eingebaut ), obwohl hash -v
. OSF / 1 /bin/sh
hatte eine type
eingebaut, die immer 0 bis OSF / 1 v3.x zurückgegeben. bash
hat kein whence
hinzugefügt, sondern ein Option auf type
zum Drucken des Pfads (type -p
entspricht whence -p
) und -a
, um alle passenden Befehle zu melden. tcsh
hat which
eingebaut und einen where
-Befehl hinzugefügt, der sich wie “ s type -a
. zsh
hat sie alle.
Die fish
Shell (2005) hat einen type
Befehl als Funktion implementiert.
Die which
Das csh-Skript wurde inzwischen aus NetBSD entfernt (da es in tcsh integriert und in anderen Shells nicht sehr nützlich ist), und die Funktionalität wurde zu whereis
hinzugefügt (wenn es als which
, whereis
verhält sich wie which
, außer dass nur ausführbare Dateien in ). In OpenBSD und FreeBSD wurde which
ebenfalls in einen in C geschriebenen Befehl geändert, der Befehle nur in $PATH
nachschlägt .
Implementierungen
Es gibt Dutzende von Implementierungen einer which
co mmand auf verschiedenen Unices mit unterschiedlicher Syntax und unterschiedlichem Verhalten.
Unter Linux (neben den integrierten in tcsh
und zsh
) finden wir mehrere Implementierungen. Auf neueren Debian-Systemen ist es beispielsweise „ein einfaches POSIX-Shell-Skript, das nach Befehlen in $PATH
sucht.
busybox
hat auch einen which
Befehl.
Es gibt einen GNU
which
ist wahrscheinlich das extravaganteste. Es versucht zu erweitern, was das Skript which
csh mit anderen Shells gemacht hat: Sie können ihm sagen, was Ihre Aliase und Funktionen sind, damit es geben kann Sie haben eine bessere Antwort (und ich glaube, einige Linux-Distributionen haben einige globale Aliase festgelegt, damit bash
dies tut).
zsh
verfügt über mehrere Operatoren , die auf den Pfad der ausführbaren Dateien erweitert werden können: den Operator =
Dateinamenerweiterung und den Operator :c
Verlaufserweiterungsmodifikator (hier angewendet auf Parametererweiterung ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, in der erstellt die Befehls-Hash-Tabelle auch als assoziatives Array commands
:
$ print -r -- $commands[ls] /bin/ls
Das Dienstprogramm whatis
(mit Ausnahme des Dienstprogramms in Unix V8 Bourne Shell oder Plan 9 rc
/ es
) ist nicht wirklich verwandt, da es nur zur Dokumentation dient (erfasst die whatis-Datenbank, das ist die Manpage-Zusammenfassung „).
whereis
war es auch hinzugefügt in 3BSD
zur gleichen Zeit wie which
, obwohl es in C
geschrieben wurde, nicht csh
und wird verwendet, um gleichzeitig die ausführbare Datei, die Manpage und die Quelle zu suchen, jedoch nicht basierend auf der aktuellen Umgebung. Dies entspricht wiederum einem anderen Bedarf.
Auf der Standardseite gibt POSIX nun die command -v
und -V
Befehle (die bis POSIX.2008 optional waren). UNIX gibt den Befehl type
an (keine Option). Das ist alles (where
, which
, whence
sind in keinem Standard angegeben)
Bis zu einer bestimmten Version waren type
und command -v
in der Linux Standard Base-Spezifikation optional, was erklärt, warum für Einige alte Versionen von posh
(obwohl sie auf pdksh
basieren, die beide hatten) hatten beide nicht. command -v
wurde auch einigen Bourne-Shell-Implementierungen hinzugefügt (wie unter Solaris).
Status heute
Der heutige Status lautet, dass type
und command -v
insgesamt allgegenwärtig sind die Bourne-ähnlichen Shells (beachten Sie jedoch, wie von @jarno bemerkt, die Einschränkung / den Fehler in bash
, wenn Sie sich nicht im POSIX-Modus befinden, oder einige Nachkommen der Almquist-Shell unten in den Kommentaren). tcsh
ist die einzige Shell, in der Sie which
verwenden möchten (da es kein type
dort und which
ist eingebaut).
In anderen Shells als tcsh
und zsh
, which
kann Ihnen den Pfad der angegebenen ausführbaren Datei mitteilen, solange in keiner unserer ~/.cshrc
, ~/.bashrc
oder eine beliebige Shell-Startdatei, und Sie definieren $PATH
nicht in Ihrer ~/.cshrc
. Wenn Sie einen Alias oder eine Funktion dafür definiert haben, kann er Ihnen davon erzählen oder nicht oder Ihnen das Falsche sagen.
Wenn Sie es wissen möchten Über alle Befehle mit einem bestimmten Namen gibt es nichts Portables. Sie würden where
in tcsh
oder zsh
, in bash
oder zsh
, whence -a
in ksh93 und in anderen Shells können Sie type
in Kombination mit which -a
verwenden, was möglicherweise funktioniert.
Empfehlungen
Abrufen des Pfadnamens zu einer ausführbaren Datei
Um den Pfadnamen einer ausführbaren Datei in einem Skript abzurufen, gibt es einige Einschränkungen:
ls=$(command -v ls)
wäre die Standardmethode.
Es gibt jedoch einige Probleme:
- Es ist nicht möglich, den Pfad der ausführbaren Datei zu kennen, ohne sie auszuführen. Alle Die
type
,which
,command -v
… alle verwenden Heuristiken, um den Pfad herauszufinden Sie durchlaufen die$PATH
-Komponenten und suchen die erste Nicht-Verzeichnisdatei, für die Sie die Ausführungsberechtigung haben Wenn Sie den Befehl ausführen, werden viele von ihnen (Bourne, AT & T ksh, zsh, ash …) nur in der Reihenfolge von ausgeführt$PATH
bis der Systemaufrufexecve
nicht mit einem Fehler zurückkehrt. Wenn beispielsweise$PATH
/foo:/bar
enthält und Siels
ausführen möchten, versuchen sie es zuerst/foo/ls
ausführen oder wenn dies fehlschlägt/bar/ls
. Jetzt kann die Ausführung von/foo/ls
fehlschlagen, da Sie keine Ausführungsberechtigung haben, aber auch aus vielen anderen Gründen, da es sich nicht um eine gültige ausführbare Datei handelt.command -v ls
meldet/foo/ls
, wenn Sie über die Ausführungsberechtigung für/foo/ls
verfügen, aberls
führt möglicherweise tatsächlich/bar/ls
aus, wenn/foo/ls
keine gültige ausführbare Datei ist. - Wenn
foo
eine integrierte Funktion oder ein Alias ist, gibtcommand -v foo
foo
zurück. Bei einigen Shells wieash
,pdksh
oderzsh
kann auchfoo
wenn$PATH
die leere Zeichenfolge enthält und sich im aktuellen Verzeichnis eine ausführbarefoo
-Datei befindet. Unter bestimmten Umständen müssen Sie dies möglicherweise berücksichtigen. Beachten Sie beispielsweise, dass die Liste der integrierten Funktionen von der Shell-Implementierung abhängt (z. B. istmount
manchmal für die Busybox integriertsh
) und beispielsweisebash
können Funktionen aus der Umgebung abrufen. - wenn
$PATH
enthält relative Pfadkomponenten (normalerweise.
oder die leere Zeichenfolge, die beide auf das aktuelle Verzeichnis verweisen, aber alles sein können), abhängig von der Shell,command -v cmd
gibt möglicherweise keinen absoluten Pfad aus. Der Pfad, den Sie zum Zeitpunkt der Ausführung von ist nicht mehr gültig, nachdem Siecd
an einer anderen Stelle. - Anekdotisch: mit der ksh93-Shell, wenn
/opt/ast/bin
(obwohl dieser genaue Pfad auf verschiedenen Systemen variieren kann, glaube ich) ist in Ihnen$PATH
, ksh93 stellt einige zusätzliche integrierte Funktionen zur Verfügung (,cmp
,cat
…), abercommand -v chmod
gibt/opt/ast/bin/chmod
zurück, auch wenn dieser Pfad nicht existiert.
Feststellen, ob ein Befehl vorhanden ist
Um herauszufinden, ob ein bestimmter Befehl standardmäßig vorhanden ist, haben Sie folgende Möglichkeiten:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Wo man which
(t)csh
verwenden möchte In csh
und tcsh
haben Sie nicht viel Auswahl. In tcsh
ist dies nicht der Fall „ist in Ordnung, da which
eingebaut ist. In csh
ist dies der Systembefehl which
, der in einigen Fällen möglicherweise nicht das tut, was Sie möchten.
Befehle nur in einigen Shells suchen
Ein Fall, in dem die Verwendung von which
sinnvoll sein kann, besteht darin, den Pfad eines Befehls zu kennen und das Potenzial zu ignorieren Shell-Einbauten oder -Funktionen in bash
, csh
(nicht tcsh
), dash
oder Bourne
Shell-Skripte, dh Shells, die keine whence -p
haben (wie ksh
oder zsh
), command -ev
(wie yash
), whatis -p
(rc
, akanga
) oder ein eingebautes which
(wie tcsh
oder zsh
) auf Systemen, auf denen which
ist verfügbar und ist nicht die csh
script.
Wenn diese Bedingungen erfüllt sind, geben Sie:
echo=$(which echo)
den Pfad der ersten echo
in $PATH
(außer in Eckfällen), unabhängig davon, ob echo
zufällig auch eine Shell ist Builtin / Alias / Function oder nicht.
In anderen Shells würden Sie Folgendes bevorzugen:
- zsh :
echo==echo
oderecho=$commands[echo]
oderecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(Vorsicht vor Pfaden mit Leerzeichen) - Fisch :
set echo (type -fp echo)
Beachten Sie, dass alles, was Sie tun möchten, run echo
müssen Sie seinen Pfad nicht ermitteln. Sie können einfach Folgendes tun:
env echo this is not echoed by the builtin echo
Zum Beispiel mit tcsh
, um zu verhindern, dass das eingebaute which
verwendet wird:
set Echo = "`env which echo`"
Wenn Sie einen externen Befehl benötigen
Ein weiterer Fall, in dem Sie which
verwenden möchten, ist, wenn Sie tatsächlich benötigen ein externer Befehl. POSIX erfordert, dass alle Shell-Buildins (wie command
) auch als externe Befehle verfügbar sind. Leider ist dies bei command
nicht der Fall Auf vielen Systemen. Beispielsweise ist es unter Linux-basierten Betriebssystemen selten, einen command
-Befehl zu finden, während die meisten von ihnen einen which
haben Befehl (obwohl verschiedene mit unterschiedlichen Optionen und Verhaltensweisen).
Fälle, in denen Sie möglicherweise einen externen Befehl wünschen, sind überall dort, wo Sie einen Befehl ausführen würden, 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, also system("command -v my-cmd")
arbeiten in ihnen. Eine Ausnahme wäre perl
, das die Shell optimiert, wenn kein Shell-Sonderzeichen (außer Leerzeichen) angezeigt wird. Dies gilt auch für den Backtick-Operator:
$ perl -le "print system "command -v emacs"" -1 $ perl -le "print system ":;command -v emacs"" /usr/bin/emacs 0 $ perl -e "print `command -v emacs`" $ perl -e "print `:;command -v emacs`" /usr/bin/emacs
Das Hinzufügen dieses :;
oben zwingt perl
, eine Shell aufzurufen Wenn Sie which
verwenden, müssen Sie diesen Trick nicht anwenden.
Kommentare
- @ Joe,
which
ist eincsh
-Skript auf vielen kommerziellen Unices. Der Grund ist historisch, dass ‚ der Grund ist, warum ich die Geschichte gegeben habe, damit die Leute verstehen, woher sie stammt, warum sich die Leute daran gewöhnt haben und warum sie tatsächlich ist kein Grund, warum Sie es verwenden sollten. Und ja, manche Leute benutzen (t) csh. Noch verwendet nicht jeder Linux - Nachdem ich diesen Beitrag gelesen habe, habe ich viel Kontext für die Antwort gefunden, aber nicht die Antwort selbst.Wo in diesem Beitrag steht tatsächlich, warum nicht
which
verwendet wird, im Gegensatz zu Dingen, die Sie möglicherweise versuchen,which
zu erledigen, der Verlauf vonwhich
, Implementierungen vonwhich
, andere Befehle zum Ausführen verwandter Aufgaben oder Gründe für die tatsächliche Verwendungwhich
? Warum sind die anderen Befehle besser ? Was machen sie anders alswhich
? Wie vermeiden sie seine Fallstricke? Diese Antwort verwendet tatsächlich mehr Wörter für die Probleme mit den Alternativen als für die Probleme mitwhich
. -
command
wird beschrieben von POSIX. - @St é phaneChazelas Wenn ich eine neue Datei mit
touch /usr/bin/mytestfile
erstelle und danachcommand -v mytestfile
gibt den Pfad an (währendwhich mytestfile
dies nicht tut). - @jarno, oh ja, Sie ‚ ist richtig.
bash
entscheidet sich für eine nicht ausführbare Datei, wenn ‚ keine ausführbare Datei finden kann, sodass ‚ s “ OK “ (obwohl man in der Praxis liebercommand -v
wäre /type
gibt einen Fehler zurück), da ‚ der Befehl ist, den es ausführen würde, wenn Siemytestfile
, aber das Verhaltendash
ist fehlerhaft, als ob ‚ eine nicht ausführbarecmd
vor einer ausführbaren Datei gibtcommand -v
die nicht ausführbare Datei zurück, während die Ausführung voncmd
die ausführbare Datei ausführt (die falsche man ist auch gehasht). FreeBSDsh
(ebenfalls basierend aufash
) hat den gleichen Fehler. zsh, yash, ksh, mksh, bash as sh sind in Ordnung.
Antwort
Die Gründe, warum man kann which
wurde nicht verwendet. Dies wurde bereits erläutert. Hier einige Beispiele für einige Systeme, bei denen which
tatsächlich fehlschlägt.
Bei Bourne-ähnlichen Shells vergleichen wir die Ausgabe von which
mit der Ausgabe von type
(type
Da es sich um eine eingebaute Shell handelt, soll dies die Grundwahrheit sein, da die Shell uns sagt, wie sie einen Befehl aufrufen würde.
Viele Fälle sind Eckfälle , aber denken Sie daran, dass which
/ type
häufig in Eckfällen verwendet werden (um die Antwort zu finden zu einem unerwarteten Verhalten wie: Warum um alles in der Welt verhält sich dieser Befehl so, welches nenne ich? ).
Die meisten Systeme, die meisten Bourne-ähnlichen Shells: Funktionen
Der offensichtlichste Fall betrifft Funktionen:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Der Grund dafür ist, dass which
nur über ausführbare Dateien und manchmal über Aliase (obwohl nicht immer die von Ihrer Shell) berichtet und nicht funktioniert.
Die GNU, deren Manpage ein fehlerhaftes Beispiel hat (da sie vergessen haben, $@
zu zitieren), wie sie auch zum Melden von Funktionen verwendet wird, aber genau wie für Aliase, da es keinen Shell-Syntax-Parser implementiert, ist es leicht zu täuschen:
$ which() { (alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@";} $ f() { echo $"\n}\ng ()\n{ echo bar;\n}\n" >> ~/foo; } $ type f f is a function f () { echo " } g () { echo bar; } " >> ~/foo } $ type g bash: type: g: not found $ which f f () { echo " } $ which g g () { echo bar; }
Die meisten Systeme, die meisten Bourne-ähnlichen Shells: Builtins
Ein weiterer offensichtlicher Fall sind Buildins oder Schlüsselwörter, da which
als externer Befehl nicht wissen kann, welche Builds Ihre Shell hat (und einige Shells wie zsh
, bash
oder ksh
können eingebaute Elemente dynamisch laden):
$ type echo . time echo is a shell builtin . is a shell builtin time is a shell keyword $ which echo . time /bin/echo which: no . in (/bin:/usr/bin) /usr/bin/time
(gilt nicht für zsh
, in dem which
eingebaut ist)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 und viele andere:
$ csh % which ls ls: aliased to ls -F % unalias ls % which ls ls: aliased to ls -F % ksh $ which ls ls: aliased to ls -F $ type ls ls is a tracked alias for /usr/bin/ls
Dies liegt daran, dass auf den meisten kommerziellen Unices which
(wie in der ursprünglichen Implementierung) on 3BSD) ist ein csh
-Skript, das ~/.cshrc
liest. Die Aliase, die gemeldet werden, sind die dort definierten, unabhängig von den aktuell definierten Aliasen und unabhängig von der Shell, die Sie tatsächlich verwenden.
In HP / UX oder Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(Die Solaris- und AIX-Versionen haben dieses Problem behoben, indem sie $path
gespeichert haben, bevor sie ~/.cshrc
und wiederherstellen, bevor die Befehle nachgeschlagen werden)
$ type "a b" a b is /home/stephane/bin/a b $ which "a b" no a in /usr/sbin /usr/bin no b in /usr/sbin /usr/bin
Oder:
$ d="$HOME/my bin" $ mkdir "$d"; PATH=$PATH:$d $ ln -s /bin/ls "$d/myls" $ type myls myls is /home/stephane/my bin/myls $ which myls no myls in /usr/sbin /usr/bin /home/stephane/my bin
(Als csh
-Skript können Sie natürlich nicht erwarten, dass es mit Argumenten funktioniert, die Leerzeichen enthalten …)
CentOS 6.4, bash
$ type which which is aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde" $ alias foo=": "|test|"" $ which foo alias foo=": "|test|"" /usr/bin/test $ alias $"foo=\nalias bar=" $ unalias bar -bash: unalias: bar: not found $ which bar alias bar="
Auf diesem System ist systemweit ein Alias definiert, der den Befehl GNU which
umschließt.
Die falsche Ausgabe liegt daran, dass which
die Ausgabe von bash
„s alias
, weiß aber nicht, wie man es richtig analysiert, und verwendet Heuristiken (ein Alias pro Zeile sucht nach dem ersten gefundenen Befehl nach einem |
, ;
, &
…)
Das Schlimmste unter CentOS ist, dass zsh
hat Ein perfekter which
eingebauter Befehl, aber CentOS hat es geschafft, ihn zu brechen, indem er durch einen nicht funktionierenden Alias für GNU which
ersetzt wurde.
Debian 7.0, ksh93:
(gilt jedoch für die meisten Systeme mit vielen Shells)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
Unter Debian /bin/which
ist ein /bin/sh
-Skript. In meinem Fall ist sh
dash
, aber es ist dasselbe, wenn es bash
.
Ein nicht gesetztes PATH
soll die PATH
Suche nicht deaktivieren, sondern die Verwendung des Systems „s Standardpfad , dem leider unter Debian niemand zustimmt (dash
und bash
haben /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 in env
) hat :/bin:/usr/bin
(ja, schaut zuerst im aktuellen Verzeichnis!))
Aus diesem Grund macht which
oben einen Fehler, da dash
die Standard PATH
unterscheidet sich von ksh93
„s
Es ist Nr t besser mit GNU which
, das meldet:
which: no which in ((null))
(interessanterweise gibt es tatsächlich eine /usr/local/bin/which
auf meinem System, bei dem es sich tatsächlich um ein akanga
-Skript handelt, das mit akanga
(ein Shell-Ableitung, wobei die Standardeinstellung PATH
/usr/ucb:/usr/bin:/bin:.
))
bash ist, jedes System:
Der eine , auf den sich Chris in seiner Antwort bezieht :
$ PATH=$HOME/bin:/bin $ ls /dev/null /dev/null $ cp /bin/ls bin $ type ls ls is hashed (/bin/ls) $ command -v ls /bin/ls $ which ls /home/chazelas/bin/ls
Auch nach dem manuellen Aufruf von hash
:
$ type -a which which is /usr/local/bin/which which is /usr/bin/which which is /bin/which $ hash -p /bin/which which $ which which /usr/local/bin/which $ type which which is hashed (/bin/which)
Nun ein Fall, in dem which
und manchmal type
schlagen fehl:
$ mkdir a b $ echo "#!/bin/echo" > a/foo $ echo "#!/" > b/foo $ chmod +x a/foo b/foo $ PATH=b:a:$PATH $ which foo b/foo $ type foo foo is b/foo
Nun mit einigen Shells:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Mit anderen:
$ foo a/foo
Weder which
noch type
kann im Voraus wissen, dass b/foo
nicht b e ausgeführt. Einige Shells wie bash
, ksh
oder yash
beim Aufrufen von foo
wird in der Tat versuchen, b/foo
auszuführen und einen Fehler zu melden, während andere (wie zsh
, ash
, csh
, Bourne
, tcsh
) wird ausgeführt a/foo
beim Ausfall des Systemaufrufs execve()
beim b/foo
.
Kommentare
-
mksh
verwendet tatsächlich etwas anderes für die Standardeinstellung$PATH
: first wird die Kompilierungszeitkonstante des Betriebssystems_PATH_DEFPATH
verwendet (am häufigsten auf den BSDs), dann wirdconfstr(_CS_PATH, …)
(POSIX) verwendet. und wenn beide nicht existieren oder fehlschlagen, wird/bin:/usr/bin:/sbin:/usr/sbin
verwendet. - In Ihrem ersten Beispiel, auch wenn
ls
ist eine Funktion, die verwendet wird gls
von PATH. Undwhich
kann Ihnen gut sagen, welches verwendet wird/usr/bin/ls
oder/usr/local/bin/ls
. Ich sehe ‚ nicht “ Warum nicht welche “ …. - @rudimeier, dass
which ls
mir/bin/ls
gibt, unabhängig davon, ob diels
ruft/bin/ls
oder/opt/gnu/bin/ls
oderdir
oder gar nichts auf. IOW,which
(das, was implementiert, IMMV) gibt etwas irrelevantes - @St é phaneChazelas. Nein nein Nein. Ich weiß bereits, dass meine
ls
eine Funktion ist. Ich weiß , dass meine Funktionls
ls
vonPATH
. Jetzt teilt mirwhich
mit, wo sich die Datei befindet. Sie sehen nur einen einzigen Anwendungsfall: “ Was würde meine Shell mit diesem Befehl tun. “ Für diesen Anwendungsfallwhich
ist falsch, richtig.Es gibt jedoch auch andere Anwendungsfälle, in denen (GNU)which
genau das Richtige ist. - @rudimeter, hängt von der
which
Implementierung. Einige werden Ihnen sagen, dass ‚ ein Alias ist (wenn Sie einen Alias konfiguriert haben oder wenn in Ihrem Haus ein~/.cshrc
vorhanden ist ein solcher Alias), einige geben Ihnen einen Weg, aber unter bestimmten Bedingungen den falschen.sh -c 'command -v ls'
, obwohl nicht perfekt, gibt Ihnen mit größerer Wahrscheinlichkeit die richtige Antwort auf diese unterschiedliche Anforderung (und ist auch Standard).
Antwort
Eine Sache, die Stephane (aus meiner kurzen Sicht) anscheinend nicht erwähnt hat, ist die, die which
hat Keine Ahnung von der Pfad-Hash-Tabelle Ihrer Shell. Dies hat zur Folge, dass möglicherweise ein Ergebnis zurückgegeben wird, das nicht repräsentativ für das ist, was tatsächlich ausgeführt wird, was das Debuggen unwirksam macht.
Antwort
Ich erschrecke normalerweise, wenn diese Frage ahnungslosen Benutzern empfohlen wird, da unbegründetes Bashing auf which
für niemanden nützlich ist.
Wenn which
funktioniert gut und bietet die richtige Antwort auf eine Aufgabe, die dem Unix-Moto folgt: eine Sache tun, es gut machen , warum sollte which
gesperrt werden?
Die Frage sollte dann sein, welche gut funktioniert und einen bestimmten Job gut erledigt?
Zum einen das externe Dienstprogramm unter / bin / which in Debian ist ein Shell-Skript, dessen Ziel es ist, nur ausführbare Dateien mit dem angegebenen Namen im Pfad aufzulisten. Ich glaube, dass which
sein beabsichtigtes Ziel korrekt erreicht. Es lädt keine Aliase, keine Funktionen, nichts aus der Shell, sondern listet nur die ersten (oder alle) ausführbaren Dateien des angegebenen Namens im PATH auf. Die bedeutet , eine Datei mit demselben Namen wie angegeben gefunden zu haben, sollte der Benutzer von ihr (ihm) herausfinden. Selbst.
Ja, andere which
-Implementierungen können (und normalerweise) bestimmte Probleme haben.
Antwort
Wir hören oft das, was vermieden werden sollte. Warum? Was sollen wir stattdessen verwenden?
Das habe ich noch nie gehört. Bitte geben Sie konkrete Beispiele an. Ich würde mir Sorgen um Ihre Linux-Distribution und die installierten Softwarepakete machen, da hier which
herkommt!
SLES 11.4 x86-64
in tcsh Version 6.18.01:
> which which which: shell built-in command.
in Bash-Version 3.2-147:
> which which /usr/bin/which > which -v GNU which v2.19, Copyright (C) 1999 - 2008 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL.
which
ist Teil von util-linux Ein Standardpaket, das von der Linux Kernel Organization zur Verwendung als Teil des Linux-Betriebssystems verteilt wird. Es bietet auch diese anderen Dateien
/bin/dmesg /bin/findmnt /bin/logger /bin/lsblk /bin/more /bin/mount /bin/umount /sbin/adjtimex /sbin/agetty /sbin/blkid /sbin/blockdev /sbin/cfdisk /sbin/chcpu /sbin/ctrlaltdel /sbin/elvtune /sbin/fdisk /sbin/findfs /sbin/fsck /sbin/fsck.cramfs /sbin/fsck.minix /sbin/fsfreeze /sbin/fstrim /sbin/hwclock /sbin/losetup /sbin/mkfs /sbin/mkfs.bfs /sbin/mkfs.cramfs /sbin/mkfs.minix /sbin/mkswap /sbin/nologin /sbin/pivot_root /sbin/raw /sbin/sfdisk /sbin/swaplabel /sbin/swapoff /sbin/swapon /sbin/switch_root /sbin/wipefs /usr/bin/cal /usr/bin/chrp-addnote /usr/bin/chrt /usr/bin/col /usr/bin/colcrt /usr/bin/colrm /usr/bin/column /usr/bin/cytune /usr/bin/ddate /usr/bin/fallocate /usr/bin/flock /usr/bin/getopt /usr/bin/hexdump /usr/bin/i386 /usr/bin/ionice /usr/bin/ipcmk /usr/bin/ipcrm /usr/bin/ipcs /usr/bin/isosize /usr/bin/line /usr/bin/linux32 /usr/bin/linux64 /usr/bin/look /usr/bin/lscpu /usr/bin/mcookie /usr/bin/mesg /usr/bin/mkzimage_cmdline /usr/bin/namei /usr/bin/rename /usr/bin/renice /usr/bin/rev /usr/bin/script /usr/bin/scriptreplay /usr/bin/setarch /usr/bin/setsid /usr/bin/setterm /usr/bin/tailf /usr/bin/taskset /usr/bin/time /usr/bin/ul /usr/bin/uname26 /usr/bin/unshare /usr/bin/uuidgen /usr/bin/wall /usr/bin/whereis /usr/bin/which /usr/bin/write /usr/bin/x86_64 /usr/sbin/addpart /usr/sbin/delpart /usr/sbin/fdformat /usr/sbin/flushb /usr/sbin/freeramdisk /usr/sbin/klogconsole /usr/sbin/ldattach /usr/sbin/partx /usr/sbin/rcraw /usr/sbin/readprofile /usr/sbin/rtcwake /usr/sbin/setctsid /usr/sbin/tunelp
meine util-linux
ist Version 2.19. Versionshinweise können leicht auf Version 2.13 vom 28. August 2007 zurückgeführt werden. Ich bin mir nicht sicher, was der Sinn oder das Ziel davon war, aber es wurde sicherlich nicht in dieser langen Sache beantwortet, die 331-mal positiv bewertet wurde.
Kommentare
- Beachten Sie, wie die Die Frage erwähnt nicht, auf welches Unix sie sich bezieht. Linux ist nur eines von wenigen.
- Wie Ihre
which -v
zeigt, ist die ‚ die GNU, die (die Extravagante) eine, die in der anderen Antwort erwähnt wurde und in keiner Weise spezifisch für Linux ist), nicht util-linux, zu dem AFAIK niemals einwhich
-Dienstprogramm enthielt. util-linux 2.19 stammt aus dem Jahr 2011, GNU 2.19 aus dem Jahr 2008.