De ce să nu folosiți “ care ”? Ce să folosim atunci?

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

  • Cred că cele mai multe argumente împotriva utilizării which presupun un context interactiv de shell. Această întrebare este etichetată / portabilitate. întrebarea în acest context ca ” ce trebuie folosit în loc de which pentru a găsi primul executabil al unui nume dat în $PATH „. Cele mai multe răspunsuri și motive împotriva which 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 .).
  • @MattBianco, da, csh (și which este încă un script csh î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 ai csh. Utilizatorii de shell-uri POSIX au command -v.
  • @rudimeier, atunci răspunsul ar fi întotdeauna, cu excepția cazului în care shell-ul dvs. este (t)csh (sau ‘ nu vă deranjează dacă ‘ nu vă oferă rezultatul corect), utilizați type sau command -v în schimb . Vedeți răspunsurile pentru de ce .
  • @rudimeier, (stat $(which ls) este greșit din mai multe motive (lipsește --, lipsă ghilimele), nu numai utilizarea which). ‘ utilizați stat -- "$(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 introdus ls) sau vă va oferi un alias așa cum este definit în configurația unor alte shell-uri …
  • @rudimeier, din nou, există o serie de condiții în care multe which implementări nu ți-ar oferi nici măcar ls care ar fi găsit printr-o căutare a $PATH (indiferent de ceea ce ls poate invoca în coajă). sh -c 'command -v ls' sau zsh -c 'rpm -q --whatprovides =ls' este mai probabil să vă ofere răspunsul corect. Ideea este că which este o moștenire ruptă de la csh.

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 $PATH până când apelul de sistem execve nu revine cu o eroare. De exemplu, dacă $PATH conține /foo:/bar și doriți să executați ls, 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 precum ash, pdksh sau zsh, se poate returna și foo dacă $PATH include șirul gol și există un fișier executabil foo î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 busybox sh) ș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ă ce cd 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 …), dar command -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 sau echo=$commands[echo] sau echo=${${:-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 script csh 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ți which de făcut, istoricul which, implementările which, alte comenzi pentru a efectua sarcini conexe sau motive pentru a utiliza efectiv which? De ce sunt celelalte comenzi mai bune ? Ce fac diferit de which? Cum evită capcanele sale? Acest răspuns cheltuiește de fapt mai multe cuvinte pentru problemele cu alternativele decât problemele cu which.
  • este descris command de POSIX.
  • @St é phaneChazelas Dacă creez un fișier nou prin touch /usr/bin/mytestfile și apoi rulez command -v mytestfile, va da calea (în timp ce which 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 prefera command -v / type returnează o eroare) ca ‘ este comanda pe care ar încerca să o execute atunci când executați mytestfile, dar comportamentul dash este eronat, ca și când ‘ este neexecutabil cmd înainte de unul executabil, command -v returnează cel neexecutabil în timp ce executarea cmd ar executa executabilul (greșit unul este, de asemenea, hash). FreeBSD sh (bazat și pe ash) 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 g ls din PATH. Și which 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 sau dir 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 mea ls apelează ls de la PATH. Acum which î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 utilizare which 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 utilitar which. util-linux 2.19 este din 2011, GNU care 2.19 este din 2008.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *