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”>
,whereisse comportă cawhichcu excepția faptului că caută numai executabile în$PATH). În OpenBSD și FreeBSD,whicha 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$PATHpână când apelul de sistemexecvenu revine cu o eroare. De exemplu, dacă$PATHconține/foo:/barși doriți să executațils, vor încerca mai întâi pentru a executa/foo/lssau dacă nu reușește/bar/ls. Acum, executarea/foo/lspoate 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 lsar raporta/foo/lsdacă aveți permisiunea de execuție pentru/foo/ls, dar ruleazălsar putea rula de fapt/bar/lsdacă/foo/lsnu este un executabil valid. - dacă
fooeste o funcție integrată sau un alias,command -v fooreturneazăfoo. Cu unele cochilii precumash,pdkshsauzsh, se poate returna șifoodacă$PATHinclude ș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,mounteste uneori încorporat pentru busyboxsh) și, de exemplu,bashpoate obține funcții din mediu. - dacă
$PATHconț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 cmds-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ă cecdaltundeva. - 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 chmodva reveni/opt/ast/bin/chmodchiar 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==echosauecho=$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,
whicheste un scriptcshpe 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țiwhichde 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
commandde 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 mytestfilenu). - @jarno, oh da, tu e corect.
bashse 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/typereturnează o eroare) ca ‘ este comanda pe care ar încerca să o execute atunci când executațimytestfile, dar comportamentuldasheste eronat, ca și când ‘ este neexecutabilcmdînainte de unul executabil,command -vreturnează cel neexecutabil în timp ce executareacmdar 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
-
mkshutilizează de fapt ceva diferit pentru$PATHimplicit: primul , se utilizează constanta de timp de compilare_PATH_DEFPATHa 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ă
lseste o funcție pe care o utilizăm glsdin PATH. Șiwhicheste bine să vă spun care dintre acestea este utilizat/usr/bin/lssau/usr/local/bin/ls. Nu ‘ nu văd ” De ce să nu folosesc care ” …. - @rudimeier, Că
which lsîmi va oferi/bin/lsindiferent dacălsapeluri de funcții/bin/lssau/opt/gnu/bin/lssaudirsau nimic. IOW,which(ceea ce implementările, IMMV) oferă ceva irelevant - @St é phaneChazelas. Nu Nu NU. Știu deja că
lseste o funcție. Știu că funcția mealsapeleazălsde 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 utilizarewhicheste greșit, corect.Dar există și alte cazuri de utilizare în care (GNU)whicheste exact ceea ce trebuie. - @rudimeter, depinde de
whichimplementare. 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.
whichpresupun un context interactiv de shell. Această întrebare este etichetată / portabilitate. întrebarea în acest context ca ” ce trebuie folosit în loc dewhichpentru a găsi primul executabil al unui nume dat în$PATH„. Cele mai multe răspunsuri și motive împotrivawhichse 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(șiwhicheste încă un scriptcshîn cele mai comerciale Unices) citește~/.cshrcatunci când nu este interactiv. ‘ este motivul pentru care ‘ observați că scripturile csh încep de obicei cu#! /bin/csh -f.whichnu 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țitypesaucommand -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ălseste într-adevăr o comandă găsită în sistemul de fișiere (nu o încorporare a shell-ului dvs. sau funcția aliasului).whichvă 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 …whichimplementări nu ți-ar oferi nici măcarlscare ar fi găsit printr-o căutare a$PATH(indiferent de ceea celspoate 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ăwhicheste o moștenire ruptă de lacsh.