Când căutați calea către un executabil sau verificați ce s-ar întâmpla dacă introduceți un nume de comandă într-un shell Unix, există o multitudine de utilități diferite ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
etc).
Auzim adesea că ar trebui evitat which
. De ce? Ce ar trebui să folosim în schimb?
Comentarii
Răspundeți
Iată tot ce nu ați crezut că nu veți dori vreodată să știți despre el:
Rezumat
Pentru a obține calea unui executabil într-un script shell de tip Bourne (există câteva avertismente; vezi mai jos):
ls=$(command -v ls)
Pentru a afla dacă există o comandă dată:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
La solicitarea unui shell interactiv de tip Bourne:
type ls
Comanda which
este o moștenire ruptă din C-Shell și este mai bine lăsată singură în shell-urile Bourne.
Cazuri de utilizare
Acolo „o distincție între căutarea acestor informații ca parte a unui script sau interactiv la promptul shell.
La promptul shell, cazul de utilizare tipic este: această comandă se comportă ciudat, folosesc corect? Ce s-a întâmplat exact când am tastat mycmd
? Pot să privesc mai departe ce este?
În acest caz, doriți să știți ce face shell-ul dvs. atunci când invocați comanda fără a invoca de fapt comanda.
În scripturile shell, tinde să fie destul de diferit. Într-un script shell nu există niciun motiv pentru care ați dori să știți unde sau ce este o comandă dacă tot ce doriți să faceți este să o rulați. În general, ceea ce doriți să știți este calea executabilului, astfel încât să puteți obține mai multe informații din acesta (cum ar fi calea către un alt fișier relativ la acesta sau să citiți informații din conținutul fișierului executabil de la acea cale).
Interactiv, poate doriți să aflați despre toate comenzile my-cmd
disponibile în sistem, în scripturi, rareori.
Majoritatea instrumentelor disponibile (așa cum se întâmplă adesea) au fost concepute pentru a fi utilizate interactiv.
Istoric
Mai întâi un pic de istorie.
Primele versiuni Unix până la sfârșitul anilor 70 nu aveau funcții sau aliasuri. Numai căutarea tradițională a executabilelor în $PATH
. csh
a introdus aliasuri în jurul anului 1978 (deși csh
a fost lansat în 2BSD
, în mai 1979), precum și procesarea unui .cshrc
pentru ca utilizatorii să personalizeze shell-ul (fiecare shell, ca csh
, citește .cshrc
chiar și atunci când nu este interactiv ca în scripturi).
În timp ce shell-ul Bourne a fost lansat pentru prima dată în Unix V7 mai devreme în 1979, suportul funcțional a fost adăugat doar mult mai târziu (1984 în SVR2) și, oricum, nu a avut niciodată un fișier rc
(.profile
este să vă configureze mediul, nu shell-ul în sine ).
csh
a devenit mult mai popular decât shell-ul Bourne ca (deși avea o sintaxă îngrozitor de proastă decât Bourne shell) adăuga multe funcții mai convenabile și mai frumoase pentru utilizare interactivă.
În 3BSD
(1980), un which
script csh a fost adăugat pentru utilizatorii csh
pentru a ajuta la identificarea unui executabil și este un script cu greu diferit pe care îl puteți găsi ca which
pe multe unități comerciale din zilele noastre (cum ar fi Solaris, HP / UX, AIX sau Tru64).
Acest script citește utilizatorul” s ~/.cshrc
(la fel ca toate scripturile csh
, cu excepția cazului în care sunt invocate cu csh -f
) și caută numele (numele) comenzii furnizate în lista de aliasuri și în $path
(matricea pe care csh
o menține pe baza $PATH
).
Iată-l: which
a fost primul pentru cel mai popular shell din acea vreme (și csh
a fost încă popular până la mijlocul Anii 90), care este principalul motiv pentru care a fost documentat în cărți și este încă utilizat pe scară largă.
Rețineți că, chiar și pentru un utilizator csh
, acel which
scriptul csh nu vă oferă neapărat informațiile corecte. Obține aliasurile definite în ~/.cshrc
, nu pe cele pe care le-ați putea defini ulterior la prompt sau, de exemplu, prin source
introducând un alt csh
și (deși nu ar fi o idee bună), PATH
ar putea fi redefinit în ~/.cshrc
.
Rularea acelei comenzi which
dintr-un shell Bourne va căuta în continuare aliasurile definite în ~/.cshrc
, dar dacă nu aveți unul deoarece nu utilizați csh
, probabil că veți obține răspunsul corect.
O funcționalitate similară nu a fost adăugată la shell Bourne până în 1984 în SVR2 cu comanda încorporată type
. Faptul că este încorporat (spre deosebire de un script extern) înseamnă că vă poate oferi informațiile corecte (într-o oarecare măsură), deoarece are acces la componentele interne ale shell-ului.
Comanda inițială type
a suferit o problemă similară scriptului which
, deoarece nu a returnat o stare de ieșire de eșec dacă comanda nu a fost găsită. De asemenea, pentru executabile, spre deosebire de which
, a generat ceva de genul ls is /bin/ls
în loc de doar /bin/ls
ceea ce a făcut mai puțin ușor de utilizat în scripturi.
Unix Versiunea 8″ s (nu a fost lansat în sălbăticie) Bourne shell avea „s type
builtin redenumit în whatis
. Și shell-ul Plan9 (viitorul succesor al Unix) rc
(și derivate precum akanga
și es
) au și whatis
.
Coaja Korn (un subset din care Definiția POSIX sh
se bazează pe), dezvoltată la mijlocul anilor 80, dar nu disponibilă pe scară largă înainte de 1988, a adăugat multe dintre caracteristicile csh
( editor de linie, aliasuri …) deasupra shell-ului Bourne. A adăugat propriul său element whence
integrat (în plus față de type
), care a luat mai multe opțiuni (-v
să furnizeze cu type
ieșire detaliată ca și -p
să caute numai executabile (nu aliasuri / funcții …) .
Coincident cu tulburările cu privire la problemele legate de drepturile de autor dintre AT & T și Berkeley, au venit câteva implementări de shell software gratuit la sfârșitul anilor 80 la începutul anilor 90.Toată shell-ul Almquist (ash
, pentru a înlocui shell-ul Bourne în BSD-uri), implementarea domeniului public al ksh
(pdksh
), bash
(sponsorizat de FSF), zsh
a ieșit între 1989 și 1991.
Ash, deși menit să fie un înlocuitor pentru shell-ul Bourne, nu a avut încorporat type
până mult mai târziu (în NetBSD 1.3 și FreeBSD 2.3 ), deși avea hash -v
. OSF / 1 /bin/sh
avea un type
încorporat care întotdeauna a returnat 0 până la OSF / 1 v3.x. bash
nu a adăugat un whence
, dar a adăugat un -p
opțiunea pentru type
pentru a imprima calea (type -p
ar fi ca whence -p
) și -a
pentru a raporta toate comenzile potrivite. tcsh
a creat which
integrat și a adăugat o comandă where
care acționează ca bash
” s type -a
. zsh
le are pe toate.
fish
shell (2005) are o comandă type
implementată ca funcție.
which
div În același timp, scriptul csh a fost eliminat de pe NetBSD (deoarece a fost încorporat în tcsh și nu prea era folosit în alte shell-uri), iar funcționalitatea a fost adăugată la whereis
„9b39b47e6e”>
,whereis
se comportă cawhich
cu excepția faptului că caută numai executabile în$PATH
). În OpenBSD și FreeBSD,which
a fost, de asemenea, modificat într-unul scris în C care caută comenzi numai în$PATH
.
Implementări
Există zeci de implementări ale unui which
mmand pe diferite Unici cu sintaxă și comportament diferit.
Pe Linux (lângă cele încorporate în tcsh
și zsh
) găsim mai multe implementări. De exemplu, pe sistemele Debian recente, „este un script shell POSIX simplu care caută comenzi în $PATH
.
busybox
are, de asemenea, o comandă which
.
Există o GNU
which
care este probabil cel mai extravagant. Încearcă să extindă ceea ce a făcut scriptul which
csh către alte shell-uri: îi poți spune care sunt aliasurile și funcțiile tale, astfel încât să poată da aveți un răspuns mai bun (și cred că unele distribuții Linux stabilesc unele aliasuri globale în jurul valorii de ca bash
să facă asta).
zsh
are câțiva operatori pentru a extinde la calea executabilelor: operatorul =
extindere nume de fișier și :c
modificator de extindere a istoricului (aplicat aici la extinderea parametrilor ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, în face, de asemenea, tabelul hash de comandă ca commands
matrice asociativă:
$ print -r -- $commands[ls] /bin/ls
Utilitarul whatis
(cu excepția celui din Unix V8 Bourne shell sau Plan 9 rc
/ es
) nu este într-adevăr legat, deoarece este doar pentru documentare (afișează baza de date whatis, adică sinopsisul paginii man).
whereis
a fost, de asemenea, adăugat în 3BSD
în același timp cu which
deși a fost scris în C
, nu csh
și este utilizat pentru a căuta în același timp, executabil, pagina de manual și sursă, dar nu pe baza mediului curent. Din nou, asta răspunde unei nevoi diferite.
Acum, pe frontul standard, POSIX specifică command -v
și -V
comenzi (care erau opționale până la POSIX.2008). UNIX specifică comanda type
(fără opțiune). Acestea sunt toate (where
, which
, whence
nu sunt specificate în niciun standard) .
Până la unele versiuni, type
și command -v
erau opționale în specificația Linux Standard Base, care explică de ce pentru de exemplu, unele versiuni vechi ale posh
(deși bazate pe pdksh
care le aveau pe ambele) nu au avut niciuna. command -v
a fost, de asemenea, adăugat la unele implementări de shell Bourne (cum ar fi Solaris).
Stare astăzi
Starea actuală este că type
și command -v
sunt omniprezente în toate cochilii asemănătoare Bourne (deși, așa cum a menționat @jarno, notați avertismentul / bug-ul în bash
atunci când nu se află în modul POSIX sau unii descendenți ai cochiliei Almquist de mai jos în comentarii). tcsh
este singurul shell unde doriți să utilizați which
(deoarece nu există type
acolo și which
este încorporat).
În cochilii, altele decât tcsh
și zsh
, which
vă poate spune calea executabilului dat atâta timp cât nu există alias sau funcție cu același nume în oricare dintre ~/.cshrc
, ~/.bashrc
sau orice fișier de pornire shell și nu definiți $PATH
în ~/.cshrc
. Dacă aveți un alias sau o funcție definită pentru acesta, acesta vă poate spune sau nu despre acesta sau vă poate spune un lucru greșit.
Dacă doriți să știți despre toate comenzile cu un nume dat, nu este nimic portabil. Ați folosi where
în tcsh
sau zsh
, type -a
în bash
sau zsh
, whence -a
în ksh93 și în alte cochilii , puteți utiliza type
în combinație cu which -a
care poate funcționa.
Recomandări
Obținerea căii spre un executabil
Acum, pentru a obține calea unui executabil într-un script, există câteva avertismente:
ls=$(command -v ls)
ar fi modalitatea standard de a face acest lucru.
Există însă câteva probleme:
- Nu este posibil să cunoaștem calea executabilului fără a o executa. Toate
type
,which
,command -v
… toți folosesc euristică pentru a afla calea . Ele parcurg componentele$PATH
și găsesc primul fișier non-director pentru care aveți permisiunea de a executa. Cu toate acestea, depe nd pe shell, atunci când vine vorba de executarea comenzii, multe dintre ele (Bourne, AT & T ksh, zsh, ash …) le vor executa în ordinea$PATH
până când apelul de sistemexecve
nu revine cu o eroare. De exemplu, dacă$PATH
conține/foo:/bar
și doriți să executațils
, vor încerca mai întâi pentru a executa/foo/ls
sau dacă nu reușește/bar/ls
. Acum, executarea/foo/ls
poate eșua, deoarece nu aveți permisiunea de execuție, dar și din multe alte motive, cum ar fi că nu este un executabil valid.command -v ls
ar raporta/foo/ls
dacă aveți permisiunea de execuție pentru/foo/ls
, dar ruleazăls
ar putea rula de fapt/bar/ls
dacă/foo/ls
nu este un executabil valid. - dacă
foo
este o funcție integrată sau un alias,command -v foo
returneazăfoo
. Cu unele cochilii precumash
,pdksh
sauzsh
, se poate returna șifoo
dacă$PATH
include șirul gol și există un fișier executabilfoo
în directorul curent. Există unele circumstanțe în care poate fi necesar să țineți cont de acest lucru. Rețineți, de exemplu, că lista de programe integrate variază în funcție de implementarea shell-ului (de exemplu,mount
este uneori încorporat pentru busyboxsh
) și, de exemplu,bash
poate obține funcții din mediu. - dacă
$PATH
conține componente ale căii relative (de obicei.
sau șirul gol care ambele se referă la directorul curent, dar ar putea fi orice), în funcție de shell,command -v cmd
s-ar putea să nu afișeze o cale absolută. Deci calea pe care o obțineți în momentul în care executați nu va mai fi valid după cecd
altundeva. - Anecdotic: cu shell-ul ksh93, dacă
/opt/ast/bin
(deși această cale exactă poate varia în funcție de diferite sisteme cred) se află în tine$PATH
, ksh93 va pune la dispoziție câteva elemente integrate suplimentare (chmod
,cmp
,cat
…), darcommand -v chmod
va reveni/opt/ast/bin/chmod
chiar dacă calea respectivă nu există.
Determinarea existenței unei comenzi
Pentru a afla dacă o comandă dată există în mod standard, puteți face:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Unde s-ar putea dori să folosiți which
(t)csh
În csh
și tcsh
, nu aveți de ales. În tcsh
, „este bine, deoarece which
este încorporat. În csh
, aceasta va fi comanda de sistem which
, care poate să nu facă ceea ce doriți în câteva cazuri.
Găsiți comenzi numai în unele shell-uri
Un caz în care ar putea avea sens să utilizați which
este dacă doriți să cunoașteți calea unei comenzi, ignorând potențialul shell builtins sau funcții în bash
, csh
(nu tcsh
), dash
, sau Bourne
scripturi shell, adică shell-uri care nu au whence -p
(cum ar fi ksh
sau zsh
), command -ev
(cum ar fi yash
), whatis -p
(rc
, akanga
) sau un built-in which
(cum ar fi tcsh
sau zsh
) pe sisteme în care which
este disponibil și nu este csh
script.
Dacă aceste condiții sunt îndeplinite, atunci:
echo=$(which echo)
vă va oferi calea primului echo
în $PATH
(cu excepția cazurilor din colț), indiferent dacă echo
se întâmplă, de asemenea, să fie un shell builtin / alias / function or not.
În alte shell-uri, ați prefera:
- zsh :
echo==echo
sauecho=$commands[echo]
sauecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(feriți-vă de căile cu spații) - pește :
set echo (type -fp echo)
Rețineți că, dacă tot ce doriți să faceți este rulați acea comandă echo
, nu trebuie să-i obțineți calea, puteți face doar:
env echo this is not echoed by the builtin echo
De exemplu, cu tcsh
, pentru a preveni încorporarea which
de la utilizarea:
set Echo = "`env which echo`"
Când aveți nevoie de o comandă externă
Un alt caz în care poate doriți să utilizați which
este atunci când de fapt aveți nevoie o comandă externă. POSIX necesită ca toate elementele încorporate ale shell-ului (cum ar fi command
) să fie disponibile și ca comenzi externe, dar, din păcate, nu este cazul pentru command
pe multe sisteme. De exemplu, este rar să găsești o comandă command
pe sisteme de operare bazate pe Linux, în timp ce majoritatea au o which
comandă (deși diferite cu opțiuni și comportamente diferite).
Cazurile în care ați putea dori o comandă externă ar fi oriunde ați executa o comandă fără a invoca un shell POSIX.
div id = „9eba3cc24b”> , popen()
… funcțiile C sau diferite limbi invocă un shell pentru a analiza acea linie de comandă, deci system("command -v my-cmd")
funcționează în ele. O excepție ar fi perl
care optimizează shell-ul dacă nu vede niciun caracter special al shell-ului (altul decât spațiul). Aceasta se aplică și operatorului său de backtick:
$ 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
Adăugarea acelui :;
de mai sus forțează perl
să invoce un shell acolo. Utilizând which
, nu ar trebui să folosiți acel truc.
Comentarii
- @Joe,
which
este un scriptcsh
pe multe Unități comerciale. Motivul este istoric, că ‘ este motivul pentru care am dat istoria, astfel încât oamenii să înțeleagă de unde a provenit, de ce oamenii s-au obișnuit să o folosească și de ce există acolo „> nu este un motiv pentru care ar trebui să îl utilizați. Și da, unii oameni folosesc (t) csh. Nu toată lumea folosește Linux încă. - După ce am citit această postare, am găsit mult context pentru răspuns, dar nu răspunsul în sine.Unde în această postare spune de fapt nu să folosiți
which
, spre deosebire de lucrurile pe care ați putea încerca să le folosițiwhich
de făcut, istoriculwhich
, implementărilewhich
, alte comenzi pentru a efectua sarcini conexe sau motive pentru a utiliza efectivwhich
? De ce sunt celelalte comenzi mai bune ? Ce fac diferit dewhich
? Cum evită capcanele sale? Acest răspuns cheltuiește de fapt mai multe cuvinte pentru problemele cu alternativele decât problemele cuwhich
. - este descris
command
de POSIX. - @St é phaneChazelas Dacă creez un fișier nou prin
touch /usr/bin/mytestfile
și apoi rulezcommand -v mytestfile
, va da calea (în timp cewhich mytestfile
nu). - @jarno, oh da, tu e corect.
bash
se va așeza pe un fișier neexecutabil dacă ‘ nu poate găsi unul executabil, deci ‘ s ” OK ” (deși în practică s-ar preferacommand -v
/type
returnează o eroare) ca ‘ este comanda pe care ar încerca să o execute atunci când executațimytestfile
, dar comportamentuldash
este eronat, ca și când ‘ este neexecutabilcmd
înainte de unul executabil,command -v
returnează cel neexecutabil în timp ce executareacmd
ar executa executabilul (greșit unul este, de asemenea, hash). FreeBSDsh
(bazat și peash
) are aceeași eroare. zsh, yash, ksh, mksh, bash as sh sunt OK.
Răspuns
Motivele pentru care se poate Nu vreau să folosesc which
au fost deja explicate, dar iată câteva exemple despre câteva sisteme în care which
eșuează de fapt.
Pe shell-urile Bourne, comparăm ieșirea which
cu ieșirea type
( fiind un shell integrat, este menit să fie adevărul de bază, deoarece shell-ul ne spune cum ar invoca o comandă).
Multe cazuri sunt colț cazuri, dar rețineți că which
/ type
sunt adesea folosite în cazuri de colț (pentru a găsi răspunsul la un comportament neașteptat de genul: de ce naibii acea comandă se comportă așa, pe care o chem? ).
Majoritatea sistemelor, majoritatea shell-urilor Bourne: funcții
Cel mai evident caz este pentru funcții:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Motivul este că which
raportează numai despre executabile și, uneori, despre aliasuri (deși nu întotdeauna cele ale shell-ului dvs. ), nu funcții.
GNU a cărui pagină de manual are un exemplu rupt (deoarece au uitat să citeze $@
) exemplu despre cum să-l utilizați pentru a raporta și funcțiile, dar la fel ca pentru pseudonime, deoarece nu implementează un parser de sintaxă a shell-ului, este ușor de păcălit:
$ 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; }
Majoritatea sistemelor, majoritatea shell-urilor Bourne: builtins
Un alt caz evident este integrat sau cuvinte cheie, deoarece which
fiind o comandă externă nu are cum să știe ce elemente integrate au shell-ul dvs. (și unele shell-uri precum zsh
, bash
sau ksh
poate încărca încorporate dinamic):
$ 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
(care nu se aplică zsh
unde which
este încorporat)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 și multe altele:
$ 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
Acest lucru se datorează faptului că pe majoritatea unităților comerciale, which
(ca în implementarea originală pe 3BSD) este un script csh
care citește ~/.cshrc
. Aliasurile pe care le va raporta sunt cele definite acolo, indiferent de aliasurile pe care le-ați definit în prezent și indiferent de shell-ul pe care îl utilizați efectiv.
În HP / UX sau Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(versiunile Solaris și AIX au rezolvat problema salvând $path
înainte de a citi ~/.cshrc
și restabilirea acestuia înainte de a căuta comanda (comenzi)
$ 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
Sau:
$ 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
(desigur, fiind un script csh
nu vă puteți aștepta să funcționeze cu argumente care conțin spații …)
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="
Pe sistemul respectiv, există un alias definit la nivel de sistem care înfășoară comanda GNU which
.
Ieșirea falsă se datorează faptului că which
citește ieșirea bash
„s alias
dar nu știe cum să o analizeze corect și folosește euristică (un alias pe linie, caută prima comandă găsită după o |
, ;
, &
…)
Cel mai rău lucru de pe CentOS este că zsh
are o comandă integrată perfect which
, dar CentOS a reușit să o rupă înlocuind-o cu un alias care nu funcționează la GNU which
.
Debian 7.0, ksh93:
(deși se aplică majorității sistemelor cu multe shell-uri)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
Pe Debian, /bin/which
este un script /bin/sh
. În cazul meu, sh
fiind dash
, dar este la fel când este „s bash
.
O setare PATH
nu este de a dezactiva căutarea PATH
, ci înseamnă utilizarea sistemului „s PATH implicit, care, din păcate, pe Debian, nimeni nu este de acord (dash
și bash
au /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
are /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
are /bin:/usr/bin
, mksh
are /usr/bin:/bin
($(getconf PATH)
), execvp()
(ca în env
) are :/bin:/usr/bin
(da, arată mai întâi în directorul curent!)) .
Motiv pentru care which
greșește mai sus, deoarece folosește dash
„implicit PATH
care este diferit de ksh93
„s
Nu este Mai bine cu GNU which
care raportează:
which: no which in ((null))
(interesant, există într-adevăr un /usr/local/bin/which
pe sistemul meu, care este de fapt un script akanga
care a venit cu akanga
(un rc
derivat de shell unde PATH
implicit este /usr/ucb:/usr/bin:/bin:.
))
bash, orice sistem:
Cel la care se referă Chris în răspunsul său :
$ 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
De asemenea, după ce ați apelat manual hash
manual:
$ 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)
Acum un caz în care which
și uneori type
eșuează:
$ 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
Acum, cu câteva cochilii:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Cu alții:
$ foo a/foo
Nici which
type
poate ști în avans că b/foo
nu poate b am executat. Unele cochilii precum bash
, ksh
sau yash
, atunci când se invocă foo
va încerca într-adevăr să ruleze b/foo
și să raporteze o eroare, în timp ce altele (cum ar fi zsh
, ash
, csh
, Bourne
, tcsh
) va rula a/foo
la eșecul apelului de sistem execve()
la b/foo
.
Comentarii
-
mksh
utilizează de fapt ceva diferit pentru$PATH
implicit: primul , se utilizează constanta de timp de compilare_PATH_DEFPATH
a sistemului de operare (cel mai frecvent pe BSD-uri), apoi se utilizeazăconfstr(_CS_PATH, …)
(POSIX), și dacă ambele nu există sau nu reușesc, se utilizează/bin:/usr/bin:/sbin:/usr/sbin
. - În primul dvs. exemplu, chiar dacă
ls
este o funcție pe care o utilizăm gls
din PATH. Șiwhich
este bine să vă spun care dintre acestea este utilizat/usr/bin/ls
sau/usr/local/bin/ls
. Nu ‘ nu văd ” De ce să nu folosesc care ” …. - @rudimeier, Că
which ls
îmi va oferi/bin/ls
indiferent dacăls
apeluri de funcții/bin/ls
sau/opt/gnu/bin/ls
saudir
sau nimic. IOW,which
(ceea ce implementările, IMMV) oferă ceva irelevant - @St é phaneChazelas. Nu Nu NU. Știu deja că
ls
este o funcție. Știu că funcția meals
apeleazăls
de laPATH
. Acumwhich
îmi spune unde este fișierul. Vedeți doar un singur caz de utilizare: ” Ce ar face shell-ul meu cu această comandă. ” Pentru acest caz de utilizarewhich
este greșit, corect.Dar există și alte cazuri de utilizare în care (GNU)which
este exact ceea ce trebuie. - @rudimeter, depinde de
which
implementare. Unii vă vor spune că ‘ este un alias (dacă aveți un alias configurat sau dacă există un~/.cshrc
în casa dvs. care are un astfel de alias), unele vă vor oferi o cale, dar cea greșită în anumite condiții.sh -c 'command -v ls'
, deși nu este perfect, este totuși mai probabil să vă ofere răspunsul corect la acea cerință diferită (și este, de asemenea, standard).
Răspuns
Un lucru pe care (din scurta mea descriere) se pare că Stephane nu l-a menționat este că which
are habar n-am despre tabelul hash al traseului shell-ului. Acest lucru are ca efect returnarea unui rezultat care nu este reprezentativ pentru ceea ce se execută de fapt, ceea ce îl face ineficient în depanare.
Răspuns
De obicei, mă înfricoșez atunci când această întrebare este recomandată utilizatorilor nebănuși, deoarece bashing-ul pe which
nu este util pentru nimeni.
Dacă which
funcționează bine și oferă răspunsul corect la anumite sarcini, urmând moto Unix: faceți un lucru, faceți-l bine , de ce ar trebui which
să fie interzis?
Întrebarea ar trebui să fie, atunci, care funcționează bine și face bine o anumită treabă?
În primul rând, utilitarul extern la / bin / care în Debian este un script shell al cărui scop este doar listarea executabilelor cu numele dat pe cale. Cred că which
își îndeplinește corect scopul dorit. Nu încarcă aliasuri, fără funcții, nimic din shell, doar listează primii (sau toți) executabilii numelui dat pe PATH. care înseamnă de a fi găsit un fișier cu același nume ca dat este ceva ce utilizatorul ar trebui să-și dea seama de ea (el) self.
Da, alte which
implementări pot (și au de obicei) să aibă probleme speciale.
Răspuns
Adesea auzim ceea ce trebuie evitat. De ce? Ce ar trebui să folosim în schimb?
Nu am auzit asta niciodată. Vă rugăm să furnizați exemple specifice. Mi-aș face griji cu privire la distribuția dvs. Linux și pachetele software instalate, deoarece de aici provine which
!
SLES 11.4 x86-64
în versiunea tcsh 6.18.01:
> which which which: shell built-in command.
în versiunea bash 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
face parte din util-linux un pachet standard distribuit de organizația Linux Kernel pentru utilizare ca parte a sistemului de operare Linux. De asemenea, oferă aceste alte fișiere
/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
util-linux
este versiunea 2.19. Notele de lansare pot fi găsite cu ușurință înapoi la v2.13 datată (28 august 2007). Nu sunt sigur care a fost scopul sau obiectivul acestui lucru, cu siguranță nu a primit răspuns în acel lucru lung votat de 331 de ori.
Comentarii
- Observați cum întrebarea nu menționează la ce se referă Unix. Linux este doar unul dintre puținele.
- După cum arată
which -v
, acel ‘ s GNU care (extravagantul unul menționat în celălalt răspuns și nu este în niciun fel specific Linux), nu util-linux care AFAIK nu a inclus niciodată un utilitarwhich
. util-linux 2.19 este din 2011, GNU care 2.19 este din 2008.
which
presupun un context interactiv de shell. Această întrebare este etichetată / portabilitate. întrebarea în acest context ca ” ce trebuie folosit în loc dewhich
pentru a găsi primul executabil al unui nume dat în$PATH
„. Cele mai multe răspunsuri și motive împotrivawhich
se ocupă de aliasuri, programe integrate și funcții, care în majoritatea scripturilor shell portabile din lumea reală sunt doar de interes academic. Aliasurile definite local nu sunt ‘ moștenite atunci când rulați un script shell (cu excepția cazului în care îl sursați cu.
).csh
(șiwhich
este încă un scriptcsh
în cele mai comerciale Unices) citește~/.cshrc
atunci când nu este interactiv. ‘ este motivul pentru care ‘ observați că scripturile csh încep de obicei cu#! /bin/csh -f
.which
nu face acest lucru deoarece își propune să vă ofere aliasurile, deoarece ‘ este menit ca un instrument pentru (interactive) utilizatori aicsh
. Utilizatorii de shell-uri POSIX aucommand -v
.(t)csh
(sau ‘ nu vă deranjează dacă ‘ nu vă oferă rezultatul corect), utilizațitype
saucommand -v
în schimb . Vedeți răspunsurile pentru de ce .stat $(which ls)
este greșit din mai multe motive (lipsește--
, lipsă ghilimele), nu numai utilizareawhich
). ‘ utilizațistat -- "$(command -v ls)"
. Asta presupune căls
este într-adevăr o comandă găsită în sistemul de fișiere (nu o încorporare a shell-ului dvs. sau funcția aliasului).which
vă poate oferi o cale greșită (nu calea pe care shell-ul dvs. o va executa dacă ați introdusls
) sau vă va oferi un alias așa cum este definit în configurația unor alte shell-uri …which
implementări nu ți-ar oferi nici măcarls
care ar fi găsit printr-o căutare a$PATH
(indiferent de ceea cels
poate invoca în coajă).sh -c 'command -v ls'
sauzsh -c 'rpm -q --whatprovides =ls'
este mai probabil să vă ofere răspunsul corect. Ideea este căwhich
este o moștenire ruptă de lacsh
.