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$PATHtillsexecvesystemanropet inte returnerar med ett fel. Till exempel om$PATHinnehåller/foo:/baroch du vill körals, försöker de först att köra/foo/lseller om det misslyckas/bar/ls. Nu kan körningen av/foo/lsmisslyckas eftersom du inte har exekveringsbehörighet men också av många andra skäl, eftersom det inte är en giltig körbar.command -v lsskulle rapportera/foo/lsom du har exekveringsbehörighet för/foo/ls, men körlskanske kör/bar/lsom/foo/lsinte är en giltig körbar. - om
fooär en inbyggd funktion eller alias, returnerarcommand -v foofoo. Med vissa skal somash,pdkshellerzshkan det också returnerafooom$PATHinnehå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 exempelbashkan få funktioner från miljön. - om
$PATHinnehå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 cmdkanske 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 ducdnå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 chmodreturnerar/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==echoellerecho=$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ändawhichatt 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. -
commandbeskrivs av POSIX. - @St é phaneChazelas Om jag skapar en ny fil med
touch /usr/bin/mytestfileoch kör sedancommand -v mytestfile, det kommer att ge sökvägen (medanwhich mytestfileinte). - @jarno, åh ja, du ’ är rätt.
bashbosä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/typereturnerar ett fel) som att ’ är kommandot som det skulle försöka utföra när du körmytestfile, mendashbeteende är buggy, som om det ’ är en icke-körbarcmdföre en körbar encommand -vreturnerar den icke-körbara medan exekvering avcmdskulle 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
-
mkshanvä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 glsfrån PATH. Ochwhichär bra att berätta vilken som används/usr/bin/lseller/usr/local/bin/ls. Jag ser inte ’ ” Varför inte använda vilken ” …. - @rudimeier, Att
which lsger mig/bin/lsoavsett omls-funktionsanrop/bin/lseller/opt/gnu/bin/lsellerdireller 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 tilllsfrånPATH. Nu sägerwhichvar 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å
whichimplementering. Vissa kommer att säga att ’ är ett alias (om du har konfigurerat ett alias eller om det finns ett~/.cshrci 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 -vvisar, ä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.
whichantar 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örwhichför att hitta den första körningen av ett givet namn i$PATH”. De flesta svar och skäl motwhichhanterar 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~/.cshrcnär de inte är interaktiva. Det är ’ varför du ’ märker att csh-skript brukar börja med#! /bin/csh -f.whichberor 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ändtypeellercommand -vistä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 attlsverkligen är ett kommando som finns i filsystemet (inte en inbyggd del av ditt skal eller en aliasfunktion).whichkan 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 …whichimplementeringar inte skulle ge dig enslssom skulle hittas genom en uppslagning av$PATH(oavsett vadlskan å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.