När du letar efter sökvägen till en körbar eller kontrollerar vad som skulle hända om du anger ett kommandonamn i ett Unix-skal, finns det en mängd olika verktyg ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
, etc).
Vi hör ofta att which
bör undvikas. Varför? Vad ska vi använda istället?
Kommentarer
Svar
Här är allt du aldrig trodde att du aldrig skulle vilja veta om det:
Sammanfattning
För att få sökväg för en körbar i ett Bourne-liknande skalskript (det finns några försiktighetsåtgärder; se nedan):
ls=$(command -v ls)
För att ta reda på om ett givet kommando finns:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Vid uppmaningen till ett interaktivt Bourne-liknande skal:
type ls
The which
-kommandot är ett trasigt arv från C-Shell och är bättre lämnat ensam i Bourne-liknande skal.
Använd fall
Där ”en åtskillnad mellan att leta efter den informationen som en del av ett skript eller interaktivt vid shellprompten.
Vid shellprompten är det typiska användningsfallet: detta kommando beter sig konstigt, använder jag rätt? Vad hände exakt när jag skrev mycmd
? Kan jag titta vidare på vad det är?
I så fall vill du veta vad ditt skal gör när du åberopar kommandot utan att faktiskt åberopa kommandot.
I skalskript tenderar det att vara helt annorlunda. I ett skalskript finns det ingen anledning till varför du vill veta var eller vad ett kommando är om allt du vill göra är att köra det. I allmänhet är det du vill veta sökvägen till den körbara filen, så att du kan få mer information ur den (som sökvägen till en annan fil i förhållande till den, eller läsa information från innehållet i den körbara filen på den vägen).
Interaktivt kanske du vill veta om alla kommandona my-cmd
som är tillgängliga i systemet, i skript, sällan så.
De flesta tillgängliga verktyg (som ofta är fallet) har utformats för att användas interaktivt.
Historia
Lite historik först.
De tidiga Unix-skalen fram till slutet av 70-talet hade inga funktioner eller alias. Endast den traditionella sökningen av körbara filer i $PATH
. csh
introducerade alias omkring 1978 (även om csh
först släpptes i 2BSD
, i maj 1979), och också behandlingen av en .cshrc
för att användare ska kunna anpassa skalet (varje skal, som csh
, läser .cshrc
även när det inte är interaktivt som i skript).
Medan Bourne-skalet först släpptes i Unix V7 tidigare 1979, tillsattes funktionsstöd bara mycket senare (1984 i SVR2), och ändå hade den aldrig någon rc
-fil (.profile
är att konfigurera din miljö, inte skalet per se ).
csh
blev mycket mer populär än Bourne-skalet som (även om det hade en väldigt sämre syntax än Bourne shell) det lade till mycket mer praktiska och trevliga funktioner för interaktiv användning.
I 3BSD
(1980), en which
csh-skript har lagts till för csh
-användarna för att hjälpa till att identifiera en körbar, och det är knappast ett annat skript som du kan hitta som which
på många kommersiella enheter idag (som Solaris, HP / UX, AIX eller Tru64).
Det manuset läser användaren” s ~/.cshrc
(som alla csh
-skript gör om de inte anropas med csh -f
) och letar upp det angivna kommandonamnet i listan med alias och i $path
(den matris som csh
upprätthåller baserat på $PATH
).
Så här: which
kom först efter det mest populära skalet vid den tiden (och csh
var fortfarande populärt fram till mitten av 90-talet), vilket är den främsta anledningen till att den dokumenterades i böcker och fortfarande används i stor utsträckning.
Observera att, även för en csh
-användare, att which
csh-skript ger dig inte nödvändigtvis rätt information. Det får de alias som definieras i ~/.cshrc
, inte de du kanske har definierat senare vid prompten eller till exempel genom att source
inge en annan csh
fil, och (även om det inte skulle vara en bra idé), PATH
kan omdefinieras i ~/.cshrc
.
Att köra det which
-kommandot från ett Bourne-skal skulle fortfarande slå upp alias definierade i ditt ~/.cshrc
om du inte har en eftersom du inte använder csh
, skulle det ändå förmodligen ge dig rätt svar.
En liknande funktionalitet lades inte till Bourne-skalet fram till 1984 i SVR2 med type
inbyggt kommando. Det faktum att det är inbyggt (i motsats till ett externt skript) betyder att det kan ge dig rätt information (till viss del) eftersom det har tillgång till skalets inre.
Det ursprungliga type
-kommandot led av ett liknande problem som which
-skriptet genom att det inte returnerade en status för felutgång om kommandot hittades inte. För körbara filer, i motsats till which
, skickar det ut något som ls is /bin/ls
istället för bara /bin/ls
vilket gjorde det mindre enkelt att använda i skript.
Unix version 8″ s (släpptes inte i naturen) Bourne-skal hade det ”s type
inbyggt namn till whatis
. Och Plan9 (en gång-efter-efterträdare för Unix) skal rc
(och dess derivat som akanga
och es
) har också whatis
.
Korn-skalet (en delmängd av vilken POSIX sh
-definitionen baseras på), utvecklad i mitten av 80-talet men inte allmänt tillgänglig före 1988, lade till många av csh
-funktionerna ( linjeditor, alias …) ovanpå Bourne-skalet. Den lade till sin egen whence
inbyggd (förutom type
) som tog flera alternativ (-v
för att tillhandahålla type
-liknande detaljerad utdata, och -p
för att bara leta efter körbara filer (inte alias / funktioner …)) .
Samtidigt med oro med avseende på upphovsrättsfrågor mellan AT & T och Berkeley, kom några fri programvara skalimplementeringar ut i slutet av 80-talet början av 90-talet.Hela Almquist-skalet (ash
, för att ersätta Bourne-skalet i BSD), det offentliga området för ksh
(pdksh
), bash
(sponsrad av FSF), zsh
kom ut mellan 1989 och 1991.
Ash, även om den skulle vara en ersättning för Bourne-skalet, hade inte en type
inbyggd förrän långt senare (i NetBSD 1.3 och FreeBSD 2.3 ), även om det hade hash -v
. OSF / 1 /bin/sh
hade en type
inbyggd returnerade 0 upp till OSF / 1 v3.x. bash
lade inte till en whence
men lade till en -p
alternativ till type
för att skriva ut sökvägen (type -p
skulle vara som whence -p
) och -a
för att rapportera alla matchande kommandon. tcsh
gjorde which
inbyggt och lade till ett where
-kommando som fungerar som bash
” s type -a
. zsh
har alla.
fish
shell (2005) har ett type
-kommando implementerat som en funktion.
which
csh-skript togs under tiden bort från NetBSD (eftersom det var inbyggt i tcsh och inte användes mycket i andra skal), och funktionaliteten lades till whereis
(när den anropas som which
, whereis
beter sig som which
förutom att den bara letar upp körbara filer i $PATH
). I OpenBSD och FreeBSD ändrades which
till en skriven i C som bara letar upp kommandon i $PATH
.
Implementeringar
Det finns dussintals implementeringar av en which
co mm och på olika enheter med olika syntax och beteende.
På Linux (bredvid de inbyggda i tcsh
och zsh
) vi hittar flera implementeringar. På nyligen gjorda Debian-system är det till exempel ett enkelt POSIX-skalskript som letar efter kommandon i $PATH
.
busybox
har också ett which
-kommando.
Det finns ett GNU
which
som förmodligen är den mest extravaganta. Den försöker utvidga vad which
csh-skriptet gjorde till andra skal: du kan berätta vad dina alias och funktioner är så att det kan ge du har ett bättre svar (och jag tror att vissa Linux-distributioner anger några globala alias runt det för bash
för att göra det).
zsh
har ett par operatörer för att expandera till sökvägen till körbara filer: operatorn =
filnamnsexpansion och :c
expansionsmodifierare för historia (här tillämpas på parameterutvidgning ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, i -modulen gör också kommandot hash-tabellen som commands
associerande array:
$ print -r -- $commands[ls] /bin/ls
Verktyget whatis
(förutom det i Unix V8 Bourne-skal eller Plan 9 rc
/ es
) är inte riktigt relaterat eftersom det bara är för dokumentation (greps whatis-databasen, det vill säga mansidans synopsis ”).
whereis
var också läggs till i 3BSD
samtidigt som which
även om det skrevs i C
, inte csh
och används för att slå upp samtidigt, körbar, man-sida och källa men inte baserat på den aktuella miljön. Så igen svarar det på ett annat behov.
Nu, på standardfronten, anger POSIX command -v
och -V
kommandon (som brukade vara valfria fram till POSIX.2008). UNIX anger kommandot type
(inget alternativ). Att ”s alla (where
, which
, whence
anges inte i någon standard) .
Upp till någon version var type
och command -v
valfria i Linux Standard Base-specifikationen vilket förklarar varför för några gamla versioner av posh
(men baserade på pdksh
som hade båda) hade inte heller någon. command -v
lades också till i vissa Bourne-skalimplementeringar (som på Solaris).
Status idag
Nuvarande status är att type
och command -v
är allmänt förekommande de Bourne-liknande skalen (dock, som noterat av @jarno, notera varningen / buggen i bash
när du inte är i POSIX-läge eller några ättlingar till Almquist-skalet nedan i kommentarer). tcsh
är det enda skalet där du vill använda which
(eftersom det inte finns någon type
där och which
är inbyggt).
I andra skal än tcsh
och zsh
, which
kan berätta vägen för den givna körbara så länge det inte finns något alias eller funktion med samma namn i någon av våra ~/.cshrc
, ~/.bashrc
eller någon shell-startfil och du definierar inte $PATH
i din ~/.cshrc
. Om du har ett alias eller en funktion definierad för det, kan det berätta om det eller inte, eller berätta fel sak.
Om du vill veta om alla kommandon med ett givet namn finns inget bärbart. Du skulle använda where
i tcsh
eller zsh
, type -a
i bash
eller zsh
, whence -a
i ksh93 och i andra skal kan du använda type
i kombination med which -a
vilket kan fungera.
Rekommendationer
Få sökväg till en körbar
Nu, för att få sökväg till en körbar i ett skript, finns det några försiktighetsåtgärder:
ls=$(command -v ls)
skulle vara det vanliga sättet att göra det.
Det finns dock några problem:
- Det går inte att känna till den körbara sökvägen utan att köra den.
type
,which
,command -v
… alla använder heuristik för att ta reda på vägen De går igenom$PATH
-komponenterna och hittar den första icke-katalogfilen som du har behörighet för. nding på skalet, när det gäller att utföra kommandot, kommer många av dem (Bourne, AT & T ksh, zsh, ash …) att exekvera dem i storleksordningen$PATH
tillsexecve
systemanropet inte returnerar med ett fel. Till exempel om$PATH
innehåller/foo:/bar
och du vill körals
, försöker de först att köra/foo/ls
eller om det misslyckas/bar/ls
. Nu kan körningen av/foo/ls
misslyckas eftersom du inte har exekveringsbehörighet men också av många andra skäl, eftersom det inte är en giltig körbar.command -v ls
skulle rapportera/foo/ls
om du har exekveringsbehörighet för/foo/ls
, men körls
kanske kör/bar/ls
om/foo/ls
inte är en giltig körbar. - om
foo
är en inbyggd funktion eller alias, returnerarcommand -v foo
foo
. Med vissa skal somash
,pdksh
ellerzsh
kan det också returnerafoo
om$PATH
innehåller den tomma strängen och det finns en körbarfoo
-fil i den aktuella katalogen. Det finns vissa omständigheter där du kan behöva ta hänsyn till det. Tänk på att listan med inbyggda enheter varierar med skalimplementeringen (till exempelmount
är ibland inbyggd för upptagenboxsh
), och till exempelbash
kan få funktioner från miljön. - om
$PATH
innehåller relativa sökvägskomponenter (typiskt.
eller den tomma strängen som båda hänvisar till den aktuella katalogen men kan vara vad som helst), beroende på skalet,command -v cmd
kanske inte matar ut en absolut sökväg. Så sökvägen du får när du kör är inte längre giltig när ducd
någon annanstans. - Anekdotisk: med ksh93-skalet, om
/opt/ast/bin
(även om den exakta sökvägen kan variera på olika system tror jag) finns i dig$PATH
, ksh93 kommer att göra några extra inbyggda tillgängliga (chmod
,cmp
,cat
…), mencommand -v chmod
returnerar/opt/ast/bin/chmod
även om den sökvägen inte finns.
Bestäm om ett kommando existerar
För att ta reda på om ett visst kommando existerar kan du göra:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Där man kanske vill använda which
(t)csh
I csh
och tcsh
har du inte mycket val. I tcsh
”s bra som which
är inbyggd. I csh
kommer det att vara kommandot which
, vilket kanske inte gör vad du vill i några få fall.
Hitta kommandon endast i vissa skal
Ett fall där det kan vara vettigt att använda which
är om du vill veta sökvägen för ett kommando och ignorera potentialen skalinbyggda funktioner eller funktioner i bash
, csh
(inte tcsh
), dash
eller Bourne
skalskript, det vill säga skal som inte har whence -p
(som ksh
eller zsh
), command -ev
(som yash
), whatis -p
(rc
, akanga
) eller en inbyggd which
(som tcsh
eller zsh
) på system där which
tillgänglig och är inte csh
script.
Om dessa villkor är uppfyllda, skulle:
echo=$(which echo)
ge dig vägen till det första echo
i $PATH
(utom i hörnfall), oavsett om echo
också råkar vara ett skal inbyggt / alias / funktion eller inte.
I andra skal skulle du föredra:
- zsh :
echo==echo
ellerecho=$commands[echo]
ellerecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(se upp för banor med mellanslag) - fisk :
set echo (type -fp echo)
Observera att om allt du vill göra är kör att echo
-kommandot, du behöver inte få sin väg, du kan bara göra:
env echo this is not echoed by the builtin echo
Till exempel med tcsh
, för att förhindra att den inbyggda which
används:
set Echo = "`env which echo`"
När du behöver ett externt kommando
Ett annat fall där du kanske vill använda which
är när du faktiskt behöver ett externt kommando. POSIX kräver att alla inbyggda skal (som command
) också är tillgängliga som externa kommandon, men tyvärr är det inte fallet för command
på många system. Det är till exempel sällsynt att hitta ett command
-kommando på Linux-baserade operativsystem medan de flesta av dem har ett which
kommando (men olika med olika alternativ och beteenden).
Fall där du kanske vill ha ett externt kommando skulle vara var du än kör ett kommando utan att anropa ett POSIX-skal.
system("some command line")
, popen()
… funktioner på C eller olika språk åberopar ett skal för att analysera kommandoraden, så system("command -v my-cmd")
fungerar i dem. Ett undantag från detta skulle vara perl
som optimerar ut skalet om det inte ser något skal-specialtecken (annat än mellanslag). Det gäller även dess backtick-operatör:
$ 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
Tillägget av det :;
ovan tvingar perl
att anropa ett skal där. Genom att använda which
, skulle du inte behöva använda det tricket.
Kommentarer
- @Joe,
which
är ettcsh
-skript på många kommersiella enheter. Anledningen är historisk, att ’ varför jag gav historien, så att folk förstår varifrån den kom, varför folk vände sig vid att använda den och varför det faktiskt ’ är ingen anledning att du ska använda den. Och ja, vissa använder (t) csh. Inte alla använder Linux ännu - Efter att ha läst det här inlägget har jag hittat mycket sammanhang för svaret, men inte själva svaret.Var i det här inlägget står det faktiskt varför inte att använda
which
, i motsats till saker du kanske försöker användawhich
att göra,which
, implementeringar avwhich
, andra kommandon för att göra relaterade uppgifter eller skäl att faktiskt användawhich
? Varför är de andra kommandona bättre ? Vad gör de annorlunda änwhich
? Hur undviker de fallgroparna? Detta svar spenderar faktiskt fler ord på problemen med alternativen än problemen medwhich
. -
command
beskrivs av POSIX. - @St é phaneChazelas Om jag skapar en ny fil med
touch /usr/bin/mytestfile
och kör sedancommand -v mytestfile
, det kommer att ge sökvägen (medanwhich mytestfile
inte). - @jarno, åh ja, du ’ är rätt.
bash
bosätter sig på en icke-körbar fil om den ’ inte hittar en körbar fil, så att den ’ s ” OK ” (men i praktiken skulle man hellrecommand -v
/type
returnerar ett fel) som att ’ är kommandot som det skulle försöka utföra när du körmytestfile
, mendash
beteende är buggy, som om det ’ är en icke-körbarcmd
före en körbar encommand -v
returnerar den icke-körbara medan exekvering avcmd
skulle köra den körbara (fel man är också hashad). FreeBSDsh
(även baserat påash
) har samma fel. zsh, yash, ksh, mksh, bash som sh är OK.
Svar
Anledningarna till varför man kan vill inte använda which
har redan förklarats, men här är några exempel på några system där which
faktiskt misslyckas.
På Bourne-liknande skal jämför vi utdata från which
med utdata från type
(type
eftersom det är ett inbyggt skal är det meningen att det ska vara markens sanning, eftersom det är skalet som berättar för oss hur det skulle åberopa ett kommando.
Många fall är hörn fall, men kom ihåg att which
/ type
ofta används i hörnfall (för att hitta svaret till ett oväntat beteende som: varför i helvete fungerar det kommandot så, vilken ringer jag? ).
De flesta system, de flesta Bourne-liknande skalen: funktioner
Det mest uppenbara fallet är för funktioner:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Anledningen är att which
bara rapporterar om körbara filer, och ibland om alias (men inte alltid de för ditt skal), inte om funktioner.
GNU: s man-sida har ett brutet (eftersom de glömde att citera $@
) exempel på hur man använder det för att rapportera funktioner också, men precis som för eftersom det inte implementerar en skal-syntax-parser, luras det lätt:
$ 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; }
De flesta system, de flesta Bourne-liknande skal: inbyggda
Ett annat uppenbart fall är inbyggda eller nyckelord, eftersom which
att vara ett externt kommando har inget sätt att veta vilka inbyggda skal som du har (och vissa skal som zsh
, bash
eller ksh
kan ladda inbyggda dynamiskt):
$ 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
(det gäller inte zsh
där which
är inbyggt)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 och många andra:
$ 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
Det beror på att de flesta kommersiella enheter which
(som i den ursprungliga implementeringen på 3BSD) är ett csh
-skript som läser ~/.cshrc
. De alias som den kommer att rapportera är de som definierats där oavsett de alias som du för närvarande har definierat och oavsett skalet du faktiskt använder.
I HP / UX eller Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(Solaris- och AIX-versionerna har åtgärdat problemet genom att spara $path
innan du läser ~/.cshrc
och återställa det innan du letar upp kommandot (erna)
$ 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
Eller:
$ 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
(naturligtvis, som ett csh
-skript kan du inte förvänta dig att det fungerar med argument som innehåller mellanslag …)
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="
På det systemet finns det ett alias definierat systemomfattande som omsluter kommandot GNU which
.
Den falska utgången beror på att which
läser utdata från bash
”s alias
men vet inte hur man analyserar det ordentligt och använder heuristik (ett alias per rad, letar efter det första hittade kommandot efter ett |
, ;
, &
…)
Det värsta på CentOS är att zsh
har ett helt fint which
inbyggt kommando men CentOS lyckades bryta det genom att ersätta det med ett icke-fungerande alias till GNU which
.
Debian 7.0, ksh93:
(men gäller de flesta system med många skal)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
På Debian, /bin/which
är ett /bin/sh
-skript. I mitt fall är sh
dash
men det är detsamma när det ”s bash
.
En avstängd PATH
är inte att inaktivera PATH
sökning, men betyder att använda systemet ”s standard PATH som tyvärr på Debian är ingen överens om (dash
och bash
har /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
har /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
har /bin:/usr/bin
, mksh
har /usr/bin:/bin
($(getconf PATH)
), execvp()
(som i env
) har :/bin:/usr/bin
(ja, ser först i den aktuella katalogen!)) .
Därför får which
fel ovan eftersom den använder dash
”s standard PATH
vilket skiljer sig från ksh93
”s
Det är ingen t bättre med GNU which
som rapporterar:
which: no which in ((null))
(intressant, det finns verkligen en /usr/local/bin/which
på mitt system som faktiskt är ett akanga
skript som följde med akanga
(ett rc
skalderivat där standard PATH
är /usr/ucb:/usr/bin:/bin:.
))
bash, vilket system som helst:
Den som Chris hänvisar till i sitt svar :
$ 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
Även efter att ha ringt hash
manuellt:
$ 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)
Nu är det fall där which
och ibland type
misslyckas:
$ 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
Nu, med några skal:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Med andra:
$ foo a/foo
Varken which
eller type
kan veta i förväg att b/foo
inte kan b exekveras. Vissa skal som bash
, ksh
eller yash
, när du anropar foo
försöker verkligen köra b/foo
och rapportera ett fel, medan andra (som zsh
, ash
, csh
, Bourne
, tcsh
) körs a/foo
vid misslyckandet av execve()
systemanrop b/foo
.
Kommentarer
-
mksh
använder faktiskt något annat för standard$PATH
: först används operativsystemets sammanställningstidskonstant_PATH_DEFPATH
(oftast på BSD: erna), sedan användsconfstr(_CS_PATH, …)
(POSIX), och om båda inte finns eller misslyckas används/bin:/usr/bin:/sbin:/usr/sbin
. - I ditt första exempel, även om
ls
är en funktion som den används i gls
från PATH. Ochwhich
är bra att berätta vilken som används/usr/bin/ls
eller/usr/local/bin/ls
. Jag ser inte ’ ” Varför inte använda vilken ” …. - @rudimeier, Att
which ls
ger mig/bin/ls
oavsett omls
-funktionsanrop/bin/ls
eller/opt/gnu/bin/ls
ellerdir
eller ingenting alls. IOW,which
(det som implementeringar, IMMV) ger något irrelevant - @St é phaneChazelas. Nej nej nej. Jag vet redan att min
ls
är en funktion. Jag vet att minls
-funktion ringer tillls
frånPATH
. Nu sägerwhich
var filen är. Du ser bara ett enstaka fall: ” Vad skulle mitt skal göra med det här kommandot. ” För detta användningsfallwhich
är fel, rätt.Men det finns andra användningsfall där (GNU)which
är exakt rätt sak. - @rudimeter beror på
which
implementering. Vissa kommer att säga att ’ är ett alias (om du har konfigurerat ett alias eller om det finns ett~/.cshrc
i ditt hem som har ett sådant alias), vissa ger dig en väg men fel under vissa förhållanden.sh -c 'command -v ls'
, men inte perfekt är fortfarande mer sannolikt att ge dig rätt svar på det annorlunda kravet (och är också standard).
Svar
En sak som (från mitt snabba skum) verkar som att Stephane inte nämnde är att which
har ingen aning om ditt skal ”hash-bord”. Detta har den effekten att det kan returnera ett resultat som inte är representativt för vad som faktiskt körs, vilket gör det ineffektivt i felsökning.
Svar
Jag kryper vanligtvis när den här frågan rekommenderas till intet ont anande användare eftersom grundlös bashing på which
inte är användbar för någon.
Om which
fungerar bra och ger rätt svar på någon uppgift, efter Unix-moto: gör en sak, gör det bra , varför ska which
vara förbjuden?
Frågan ska då vara vilken som fungerar bra och gör ett specifikt jobb bra?
För en, det externa verktyget vid / bin / vilket i Debian är ett skalskript vars mål bara är att lista körbara filer med det angivna namnet på sökvägen. Jag tror att which
gör sitt avsedda mål korrekt. Det laddar inga alias, inga funktioner, ingenting från skalet, bara listar de första (eller alla) körbarheterna med det angivna namnet på PATH. som betyder för att ha hittat en fil med samma namn som angiven är något som användaren bör räkna ut av henne (honom) själv.
Ja, andra which
implementeringar kan (och vanligtvis gör) ha särskilda problem.
Svar
Vi hör ofta det som bör undvikas. Varför? Vad ska vi använda istället?
Det har jag aldrig hört. Ge specifika exempel. Jag skulle oroa mig för din linuxdistribution och installerade mjukvarupaket, eftersom det är där which
kommer ifrån!
SLES 11,4 x86-64
i tcsh-version 6.18.01:
> which which which: shell built-in command.
i 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
är en del av util-linux ett standardpaket distribuerat av Linux Kernel Organization för användning som en del av Linux-operativsystemet. Det ger också dessa andra filer
/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
min util-linux
är version 2.19. Utgivningsanmärkningar kan enkelt hittas tillbaka till v2.13 daterad (28-aug-2007). Inte säker på vad poängen eller målet med detta var, det besvarades verkligen inte den långa saken som röstades upp 331 gånger.
Kommentarer
- Lägg märke till hur frågan nämns inte vad Unix det hänvisar till. Linux är bara ett av några få.
- Som din
which -v
visar, är ’ GNU som (den extravaganta en nämns i det andra svaret och är inte på något sätt specifik för Linux), inte util-linux som AFAIK aldrig inkluderade ettwhich
-verktyg. util-linux 2.19 är från 2011, GNU som 2.19 är från 2008.
which
antar ett interaktivt skalkontext. Denna fråga är taggad / portabilitet. Så jag tolkar frågan i detta sammanhang som ” vad man ska använda istället förwhich
för att hitta den första körningen av ett givet namn i$PATH
”. De flesta svar och skäl motwhich
hanterar alias, inbyggda funktioner och funktioner som i de flesta bärbara skalskript i verkligheten bara är av akademiskt intresse. Lokalt definierade alias är inte ’ t ärvda när du kör ett skalskript (såvida du inte köper det med.
).csh
(ochwhich
är fortfarande ettcsh
-skript på de flesta kommersiella Unices) läser~/.cshrc
när de inte är interaktiva. Det är ’ varför du ’ märker att csh-skript brukar börja med#! /bin/csh -f
.which
beror inte på att det syftar att ge dig aliaserna, eftersom det ’ är avsett som ett verktyg för (interaktiva) användare avcsh
. POSIX-skalanvändare harcommand -v
.(t)csh
(eller tänker du ’ t om det inte ’ t ger dig rätt resultat), användtype
ellercommand -v
istället . Se svaren för varför .stat $(which ls)
är fel av flera skäl (saknas--
, saknade citat), inte bara användningen avwhich
). Du ’ använderstat -- "$(command -v ls)"
. Det förutsätter attls
verkligen är ett kommando som finns i filsystemet (inte en inbyggd del av ditt skal eller en aliasfunktion).which
kan ge dig fel väg (inte den sökväg som ditt skal skulle utföra om du angavls
) eller ge dig ett alias som definierat i konfigurationen av några andra skal …which
implementeringar inte skulle ge dig ensls
som skulle hittas genom en uppslagning av$PATH
(oavsett vadls
kan åberopa i ditt skal).sh -c 'command -v ls'
ellerzsh -c 'rpm -q --whatprovides =ls'
är mer benägna att ge dig rätt svar. Poängen här är attwhich
är ett trasigt arv fråncsh
.