Perché non utilizzare “ quale ”? Cosa usare allora?

Quando si cerca il percorso di un eseguibile o si controlla cosa succederebbe se si immette un nome di comando in una shell Unix, ci “una pletora di diverse utilità ( which, type, command, whence, where, whereis, whatis, hash, ecc.).

Si sente spesso dire che which dovrebbe essere evitato. Perché? Cosa dovremmo usare invece?

Commenti

  • Penso che la maggior parte degli argomenti contro lutilizzo di which presumono un contesto di shell interattivo. Questa domanda è contrassegnata / portabilità. Quindi interpreto la domanda in questo contesto come ” cosa usare invece di which per trovare il primo eseguibile di un determinato nome nel $PATH “. La maggior parte delle risposte e dei motivi contrari which si occupa di alias, builtin e funzioni, che nella maggior parte degli script di shell portatili del mondo reale sono solo di interesse accademico. Gli alias definiti a livello locale vengono ‘ t ereditati durante lesecuzione di uno script di shell (a meno che non lo si provenga con .).
  • @MattBianco, sì, csh (e which è ancora uno script csh nella maggior parte degli annunci commerciali Unices) legge ~/.cshrc quando non interattivo. Questo ‘ è il motivo per cui ‘ noterai che gli script csh di solito iniziano con #! /bin/csh -f. which non lo fa perché mira a darti gli alias, perché ‘ è inteso come uno strumento per utenti (interattivi) di csh. Gli utenti di shell POSIX hanno command -v.
  • @rudimeier, quindi la risposta sarebbe sempre a meno che la tua shell non sia (t)csh (o ‘ non ti dispiace se ‘ non ti dà il risultato corretto), utilizza type o command -v invece . Consulta le risposte al perché .
  • @rudimeier, (stat $(which ls) è sbagliato per diversi motivi (manca --, virgolette mancanti), non solo luso di which). ‘ d utilizzare stat -- "$(command -v ls)". Ciò presuppone che ls sia effettivamente un comando trovato nel file system (non un builtin della shell o una funzione di alias). which potrebbe darti il percorso sbagliato (non il percorso che la tua shell eseguirà se inserissi ls) o ti fornirà un alias come definito nella configurazione di altre shell …
  • @rudimeier, ancora una volta, ci sono una serie di condizioni in cui molte implementazioni di which non ti darebbero nemmeno il ls che verrebbe trovato da una ricerca di $PATH (indipendentemente da cosa ls può invocare nella tua shell). sh -c 'command -v ls' o zsh -c 'rpm -q --whatprovides =ls' hanno maggiori probabilità di darti la risposta corretta. Il punto qui è che which è uneredità spezzata di csh.

Rispondi

Ecco tutto quello che non avresti mai pensato di non voler sapere:

Riepilogo

Per ottenere il nome del percorso di un eseguibile in uno script di shell simile a Bourne (ci sono alcune avvertenze; vedi sotto):

ls=$(command -v ls) 

Per scoprire se un dato comando esiste:

if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi 

Al prompt di una shell interattiva simile a Bourne:

type ls 

Il Il comando which è uneredità non funzionante della C-Shell ed è meglio lasciarlo solo nelle shell tipo Bourne.

Casi duso

Lì “una distinzione tra la ricerca di tali informazioni come parte di uno script o in modo interattivo al prompt della shell.

Al prompt della shell, il caso duso tipico è: questo comando si comporta in modo strano, sto usando il giusto? Che cosa è successo esattamente quando ho digitato mycmd? Posso esaminare ulteriormente di cosa si tratta?

In tal caso, vuoi sapere cosa fa la tua shell quando invoca il comando senza effettivamente invocare il comando.

Negli script di shell, tende ad essere abbastanza diverso. In uno script di shell non cè motivo per cui vuoi sapere dove o cosa sia un comando se tutto ciò che vuoi fare è eseguirlo. In generale, quello che vuoi sapere è il percorso delleseguibile, in modo da poter ottenere più informazioni da esso (come il percorso di un altro file relativo a quello, o leggere le informazioni dal contenuto del file eseguibile in quel percorso).

In modo interattivo, potresti voler conoscere tutti i comandi my-cmd disponibili sul sistema, negli script, raramente così.

La maggior parte degli strumenti disponibili (come spesso accade) sono stati progettati per essere utilizzati in modo interattivo.

Storia

Prima un po di storia.

Le prime shell Unix fino alla fine degli anni 70 non avevano funzioni o alias. Solo la tradizionale ricerca di eseguibili in $PATH. csh ha introdotto gli alias intorno al 1978 (sebbene csh sia stato rilasciato per la prima volta in 2BSD, nel maggio 1979) e anche lelaborazione di un .cshrc per consentire agli utenti di personalizzare la shell (ogni shell, come csh , legge .cshrc anche quando non è interattivo come negli script).

Mentre la shell Bourne è stata rilasciata per la prima volta in Unix V7 allinizio del 1979, il supporto delle funzioni è stato aggiunto solo molto più tardi (1984 in SVR2), e comunque non ha mai avuto alcun file rc (.profile serve a configurare il tuo ambiente, non la shell di per sé ).

csh è diventato molto più popolare della Bourne shell in quanto (sebbene avesse una sintassi terribilmente peggiore della Bourne shell) aggiungeva molte funzionalità più utili e interessanti per luso interattivo.

In 3BSD (1980), un which script csh è stato aggiunto per gli utenti csh per identificare un eseguibile, ed è “uno script difficilmente diverso che puoi trovare come which su molti Unix commerciali oggigiorno (come Solaris, HP / UX, AIX o Tru64).

Quello script legge lutente” s ~/.cshrc (come tutti gli script csh a meno che non vengano richiamati con csh -f) e cerca i nomi dei comandi forniti nellelenco di alias e in $path (larray che csh mantiene basato su $PATH).

Ecco qui: which è arrivato primo per la shell più popolare allepoca (e csh era ancora popolare fino a metà Anni 90), che è il motivo principale per cui è stato documentato nei libri ed è ancora ampiamente utilizzato.

Tieni presente che, anche per un utente csh, which lo script csh non ti fornisce necessariamente le giuste informazioni. Ottiene gli alias definiti in ~/.cshrc, non quelli che potresti aver definito successivamente al prompt o, ad esempio, source in un altro csh file e (anche se non sarebbe una buona idea), PATH potrebbe essere ridefinito in ~/.cshrc.

Lesecuzione di quel comando which da una shell Bourne continuerebbe a cercare gli alias definiti nel tuo ~/.cshrc, ma se non ne hai uno perché non usi csh, probabilmente otterrai comunque la risposta giusta.

Una funzionalità simile non è stata aggiunta a la Bourne shell fino al 1984 in SVR2 con il comando incorporato type. Il fatto che sia integrato (al contrario di uno script esterno) significa che può darti le informazioni giuste (in una certa misura) poiché ha accesso alle parti interne della shell.

Il comando type presentava un problema simile a quello dello script which in quanto non restituiva uno stato di uscita non riuscito se il comando non è stato trovato. Inoltre, per gli eseguibili, contrariamente a which, restituisce qualcosa come ls is /bin/ls invece di /bin/ls che lo rendeva meno facile da usare negli script.

La versione Unix 8″ s (non rilasciata allo stato brado) la Bourne shell aveva “s type builtin rinominato in whatis. E la shell di Plan9 (il successore di Unix) rc (e il suo derivati come akanga e es) hanno anche whatis.

La shell Korn (un sottoinsieme di cui il La definizione POSIX sh si basa su), sviluppata a metà degli anni 80 ma non ampiamente disponibile prima del 1988, ha aggiunto molte delle csh funzionalità ( editor di riga, alias …) sopra la shell Bourne. Ha aggiunto il proprio whence integrato (oltre a type) che richiedeva diverse opzioni (-v per fornire un output dettagliato simile a type e -p per cercare solo eseguibili (non alias / funzioni …)) .

In coincidenza con le turbolenze per quanto riguarda i problemi di copyright tra AT & T e Berkeley, sono arrivate alcune implementazioni di shell software libero alla fine degli anni 80 allinizio degli anni 90.Tutta la shell Almquist (ash, in sostituzione della shell Bourne nei BSD), limplementazione di dominio pubblico di ksh (pdksh), bash (sponsorizzato dalla FSF), zsh è uscito tra il 1989 e il 1991.

Ash, sebbene pensato per essere un sostituto per la shell Bourne, non aveva un type integrato fino a molto tempo dopo (in NetBSD 1.3 e FreeBSD 2.3 ), sebbene avesse hash -v. OSF / 1 /bin/sh aveva un type integrato che sempre ha restituito 0 fino a OSF / 1 v3.x. bash non ha aggiunto un whence ma ha aggiunto un -p opzione per type per stampare il percorso (type -p sarebbe come whence -p) e -a per segnalare tutti i comandi corrispondenti. tcsh ha integrato which e ha aggiunto un comando where che agisce come bash” s type -a. zsh li ha tutti.

fish shell (2005) ha un comando type implementato come funzione.

Il which lo script csh nel frattempo è stato rimosso da NetBSD (poiché era integrato in tcsh e di scarsa utilità in altre shell) e la funzionalità aggiunta a whereis (se invocata come which, whereis si comporta come which tranne per il fatto che cerca solo eseguibili in $PATH). In OpenBSD e FreeBSD, which è stato anche cambiato in uno scritto in C che cerca i comandi solo in $PATH .

Implementazioni

Esistono dozzine di implementazioni di un which co mmand su vari Unix con sintassi e comportamento differenti.

Su Linux (oltre a quelli incorporati in tcsh e zsh ) troviamo diverse implementazioni. Sui recenti sistemi Debian, ad esempio, è “un semplice script di shell POSIX che cerca comandi in $PATH.

busybox ha anche un which comando.

Esiste un GNU which che è probabilmente il più stravagante. Cerca di estendere ciò che lo script which csh ha fatto ad altre shell: puoi dirgli quali sono i tuoi alias e le tue funzioni in modo che possa dare sei una risposta migliore (e credo che alcune distribuzioni Linux impostino alcuni alias globali attorno a questo per bash per farlo).

zsh ha un paio di operatori da espandere nel percorso degli eseguibili: loperatore = espansione del nome file e loperatore :c modificatore di espansione della cronologia (qui applicato all espansione del parametro ):

$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls 

zsh, nel rende anche la tabella hash dei comandi come commands array associativo:

$ print -r -- $commands[ls] /bin/ls 

Lutilità whatis (ad eccezione di quella in Unix V8 Bourne shell o Plan 9 rc / es) non è realmente correlato in quanto è solo per la documentazione (greps il database whatis, che è la sinossi della pagina man “).

whereis era anche aggiunto in 3BSD contemporaneamente a which sebbene fosse scritto in C, non csh e viene utilizzato per cercare contemporaneamente leseguibile, la pagina man e il sorgente ma non in base allambiente corrente. Quindi, di nuovo, questo risponde a unesigenza diversa.

Ora, sul fronte standard, POSIX specifica command -v e -V comandi (che erano opzionali fino a POSIX.2008). UNIX specifica il comando type (nessuna opzione). Questo è tutto (where, which, whence non sono specificati in nessuno standard) .

Fino a qualche versione, type e command -v erano opzionali nella specifica Linux Standard Base, il che spiega perché per Ad esempio, alcune vecchie versioni di posh (sebbene basate su pdksh che aveva entrambe) “non avevano neanche”. command -v è stato aggiunto anche ad alcune implementazioni di Bourne shell (come su Solaris).

Stato attuale

Lo stato attuale è che type e command -v sono onnipresenti in tutti le shell simili a Bourne (sebbene, come notato da @jarno, notare lavvertenza / bug in bash quando non è in modalità POSIX o alcuni discendenti della shell Almquist di seguito nei commenti). tcsh è lunica shell in cui vorresti utilizzare which (poiché non cè type lì e which è integrato).

Nelle shell diverse da tcsh e zsh, which potrebbe indicarti il percorso di un dato eseguibile purché non ci siano alias o funzioni con lo stesso nome in nessuno dei nostri ~/.cshrc, ~/.bashrc o qualsiasi file di avvio della shell e non “t definire $PATH nel tuo ~/.cshrc. Se hai definito un alias o una funzione, potrebbe o meno parlartene o dirti la cosa sbagliata.

Se vuoi sapere riguardo a tutti i comandi con un dato nome, non cè niente di portatile. “D utilizzare where in tcsh o zsh, type -a in bash o zsh, whence -a in ksh93 e in altre shell , puoi utilizzare type in combinazione con which -a che potrebbe funzionare.

Consigli

Ottenere il percorso di un eseguibile

Ora, per ottenere il percorso di un eseguibile in uno script, ci sono alcune avvertenze:

ls=$(command -v ls) 

sarebbe il modo standard per farlo.

Ci sono però alcuni problemi:

  • Non è possibile conoscere il percorso delleseguibile senza eseguirlo. Tutti type, which, command -v … usano tutti leuristica per trovare il percorso . Passano in rassegna i componenti $PATH e trovano il primo file non di directory per il quale si dispone dellautorizzazione di esecuzione. Tuttavia, depe Trovando sulla shell, quando si tratta di eseguire il comando, molti di essi (Bourne, AT & T ksh, zsh, ash …) li eseguiranno semplicemente nellordine di $PATH finché la chiamata di sistema execve non restituisce un errore. Ad esempio, se $PATH contiene /foo:/bar e desideri eseguire ls, proveranno prima per eseguire /foo/ls o se non riesce /bar/ls. Ora lesecuzione di /foo/ls potrebbe non riuscire perché non hai il permesso di esecuzione ma anche per molti altri motivi, come se non fosse un eseguibile valido. command -v ls segnalerebbe /foo/ls se disponi dellautorizzazione di esecuzione per /foo/ls, ma in esecuzione ls potrebbe effettivamente essere eseguito /bar/ls se /foo/ls non è un eseguibile valido.
  • se foo è un builtin, una funzione o un alias, command -v foo restituisce foo. Con alcune shell come ash, pdksh o zsh, potrebbe anche restituire foo se $PATH include la stringa vuota e cè un file eseguibile foo nella directory corrente. Ci sono alcune circostanze in cui potresti dover tenerne conto. Tieni presente, ad esempio, che lelenco dei incorporati varia con limplementazione della shell (ad esempio, mount a volte è incorporato per busybox sh) e, ad esempio, bash può ottenere funzioni dallambiente.
  • if $PATH contiene componenti del percorso relativo (in genere . o la stringa vuota che si riferiscono entrambi alla directory corrente ma potrebbero essere qualsiasi cosa), a seconda della shell, command -v cmd potrebbe non restituire un percorso assoluto. Pertanto, il percorso ottenuto al momento dellesecuzione di non sarà più valido dopo aver cd altrove.
  • Aneddotica: con la shell ksh93, se /opt/ast/bin (sebbene quel percorso esatto possa variare su sistemi diversi, credo) è in te $PATH, ksh93 renderà disponibili alcuni incorporati extra (chmod, cmp, cat …), ma command -v chmod restituirà /opt/ast/bin/chmod anche se il percorso “non esiste.

Determinare se un comando esiste

Per scoprire se un dato comando esiste in modo standard, puoi fare:

if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi 

Dove si potrebbe voler utilizzare which

(t)csh

In csh e tcsh non hai molta scelta. In tcsh, “Va bene perché which è integrato. In csh, quello sarà il comando di sistema which, che in alcuni casi potrebbe non fare ciò che desideri.

Trova comandi solo in alcune shell

Un caso in cui potrebbe avere senso usare which è se vuoi conoscere il percorso di un comando, ignorando il potenziale incorporati della shell o funzioni in bash, csh (non tcsh), dash o Bourne script di shell, ovvero shell che non hanno whence -p (come ksh o zsh), command -ev (come yash ), whatis -p (rc, akanga) o un which (come tcsh o zsh) sui sistemi in cui which è disponibile e non è csh.

Se queste condizioni sono soddisfatte, allora:

echo=$(which echo) 

ti darebbe il percorso del primo echo in $PATH (tranne nei casi dangolo), indipendentemente dal fatto che echo sia anche una shell builtin / alias / function oppure no.

In altre shell, preferisci:

  • zsh : echo==echo o echo=$commands[echo] o echo=${${:-echo}:c}
  • ksh , zsh : echo=$(whence -p echo)
  • yash : echo=$(command -ev echo)
  • rc , akanga : echo=`whatis -p echo` (attenzione ai percorsi con spazi)
  • pesce : set echo (type -fp echo)

Tieni presente che se tutto ciò che vuoi fare è correre quel comando echo, non è necessario che tu ne riceva il percorso, puoi semplicemente fare:

env echo this is not echoed by the builtin echo 

Ad esempio, con tcsh, per impedire lutilizzo del which incorporato:

set Echo = "`env which echo`" 

Quando hai bisogno di un comando esterno

Un altro caso in cui potresti voler usare which è quando effettivamente hai bisogno un comando esterno. POSIX richiede che tutti i built-in della shell (come command) siano disponibili anche come comandi esterni, ma sfortunatamente, questo non è il caso di command su molti sistemi. Ad esempio, è raro trovare un comando command su sistemi operativi basati su Linux mentre la maggior parte di essi ha un which (sebbene differenti con differenti opzioni e comportamenti).

I casi in cui potresti volere un comando esterno sarebbero dovunque tu eseguiresti un comando senza richiamare una shell POSIX.

Il system("some command line"), popen() … le funzioni di C o di vari linguaggi invocano una shell per analizzare quella riga di comando, quindi system("command -v my-cmd") ci lavorano. Uneccezione sarebbe perl che ottimizza la shell se non vede alcun carattere speciale della shell (diverso dallo spazio). Ciò vale anche per il suo operatore 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 

Laggiunta di quanto :; sopra costringe perl a richiamare una shell lì. Utilizzando which, non dovresti “utilizzare questo trucco.

Commenti

  • @Joe, which è uno script csh su molti Unix commerciali. Il motivo è storico, che ‘ è il motivo per cui ho fornito la cronologia, così le persone capiscono da dove proviene, perché le persone si sono abituate a usarla e perché effettivamente ‘ non è un motivo per cui dovresti usarlo. E sì, alcune persone usano (t) csh. Non tutti usano ancora Linux
  • Dopo aver letto questo post, ho trovato molto contesto per la risposta, ma non la risposta stessa.Dove in questo post viene effettivamente detto perché non utilizzare which, in contrasto con le cose che potresti provare a utilizzare which da fare, la cronologia di which, le implementazioni di which, altri comandi per eseguire attività correlate o motivi per utilizzarli effettivamente which? Perché gli altri comandi sono migliori ? Che cosa fanno di diverso da which? Come evitano le sue insidie? Questa risposta in realtà spende più parole sui problemi con le alternative rispetto ai problemi con which.
  • command è descritto di POSIX.
  • @St é phaneChazelas Se creo un nuovo file da touch /usr/bin/mytestfile e successivamente eseguo command -v mytestfile, fornirà il percorso (mentre which mytestfile no).
  • @jarno, oh sì, tu ‘ a destra. bash stabilirà un file non eseguibile se ‘ non ne trova uno eseguibile, quindi ‘ s ” OK ” (anche se in pratica si preferisce command -v / type restituisce un errore) poiché ‘ è il comando che tenterebbe di eseguire quando esegui mytestfile, ma il comportamento dash è difettoso, come se ‘ non fosse eseguibile cmd prima di un eseguibile, command -v restituisce quello non eseguibile mentre lesecuzione di cmd eseguirà quello eseguibile (quello sbagliato uno è anche sottoposto ad hashing). FreeBSD sh (anchesso basato su ash) ha lo stesso bug. zsh, yash, ksh, mksh, bash as sh sono OK.

Answer

I motivi per cui si può non voglio utilizzare which sono già stati spiegati, ma qui ci sono alcuni esempi su alcuni sistemi in cui which in realtà non funziona.

Su shell simili a Bourne, stiamo “confrontando loutput di which con loutput di type (type essendo un builtin di shell, è pensato per essere la verità fondamentale, poiché è la shell che ci dice come invocerebbe un comando).

Molti casi sono casi dangolo , ma tieni presente che which / type sono spesso usati nei casi dangolo (per trovare la risposta a un comportamento inaspettato come: perché mai quel comando si comporta così, quale sto chiamando? ).

La maggior parte dei sistemi, la maggior parte delle shell Bourne: functions

Il caso più ovvio è per le funzioni:

$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls 

Il motivo è che which riporta solo gli eseguibili e talvolta gli alias (sebbene non sempre quelli della tua shell), non le funzioni.

Lesempio GNU la cui pagina man ha un errore (poiché si sono dimenticati di citare $@) su come usarlo anche per riportare funzioni, ma proprio come per alias, poiché non implementa un parser della sintassi della shell, è facilmente ingannabile:

$ 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; } 

La maggior parte dei sistemi, la maggior parte delle shell Bourne: builtins

Un altro caso ovvio sono i comandi incorporati o le parole chiave, poiché which essendo un comando esterno non ha modo di sapere quale comando ha la tua shell (e alcune shell come zsh, bash o ksh possono caricare i incorporati dinamicamente):

$ 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 

(che non “si applica a zsh dove which è incorporato)

Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 e molti altri:

$ 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 

Questo perché sulla maggior parte degli Unix commerciali, which (come nellimplementazione originale su 3BSD) è uno csh script che legge ~/.cshrc. Gli alias che riporterà sono quelli definiti lì indipendentemente dagli alias che hai attualmente definito e indipendentemente dalla shell che stai effettivamente utilizzando.

In HP / UX o Tru64:

% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls 

(le versioni Solaris e AIX hanno risolto il problema salvando $path prima di leggere il ~/.cshrc e ripristinarlo prima di cercare i comandi)

$ 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 

Oppure:

$ 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 

(ovviamente, essendo uno script csh non puoi “aspettarti che funzioni con argomenti contenenti spazi …)

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=" 

Su quel sistema, esiste un alias definito a livello di sistema che racchiude il comando GNU which.

Loutput fasullo è perché which legge loutput di bash “s alias ma non sa come analizzarlo correttamente e utilizza leuristica (un alias per riga, cerca il primo comando trovato dopo un |, ;, & …)

La cosa peggiore su CentOS è che zsh ha un comando integrato which perfettamente funzionante ma CentOS è riuscito a interromperlo sostituendolo con un alias non funzionante per GNU which.

Debian 7.0, ksh93:

(sebbene si applichi alla maggior parte dei sistemi con molte shell)

$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which 

Su Debian, /bin/which è uno script /bin/sh. Nel mio caso, sh è dash ma “è lo stesso quando è” bash.

Un PATH non impostato non deve disabilitare la ricerca PATH, ma significa utilizzare il sistema “s PATH predefinito su cui purtroppo su Debian nessuno è daccordo (dash e bash hanno /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, zsh ha /bin:/usr/bin:/usr/ucb:/usr/local/bin, ksh93 ha /bin:/usr/bin, mksh has /usr/bin:/bin ($(getconf PATH)), execvp() (come in env) ha :/bin:/usr/bin (sì, cerca prima nella directory corrente!)) .

Questo è il motivo per cui which si sbaglia sopra poiché “utilizza dash” il PATH che è diverso da ksh93 “s

No t meglio con GNU which che riporta:

which: no which in ((null)) 

(interessante, cè davvero un /usr/local/bin/which sul mio sistema che in realtà è uno script akanga fornito con akanga (un rc derivato della shell in cui il valore predefinito PATH è /usr/ucb:/usr/bin:/bin:.))

bash, qualsiasi sistema:

Quello a cui si riferisce Chris nella sua risposta :

$ 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 

Anche dopo aver chiamato hash manualmente:

$ 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) 

Ora un caso in cui which e talvolta type fallisce:

$ 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 

Ora, con alcune shell:

$ foo bash: ./b/foo: /: bad interpreter: Permission denied 

Con altri:

$ foo a/foo 

whichtype può sapere in anticipo che b/foo non può b e eseguito. Alcune shell come bash, ksh o yash, quando si richiama foo proverà effettivamente a eseguire b/foo e segnalare un errore, mentre altri (come zsh, ash, csh, Bourne, tcsh) verrà eseguito a/foo in caso di errore della execve() chiamata di sistema su b/foo.

Commenti

  • mksh utilizza effettivamente qualcosa di diverso per limpostazione predefinita $PATH: first , viene utilizzata la costante del tempo di compilazione del sistema operativo _PATH_DEFPATH (più comunemente sui BSD), quindi viene utilizzato confstr(_CS_PATH, …) (POSIX), e se entrambi non esistono o falliscono, viene utilizzato /bin:/usr/bin:/sbin:/usr/sbin.
  • Nel tuo primo esempio, anche se ls è una funzione che sta utilizzando g ls da PATH. E which va bene per dirti quale è utilizzato /usr/bin/ls o /usr/local/bin/ls. Non ‘ non vedo ” Perché non uso quale ” ….
  • @rudimeier, che which ls mi darà /bin/ls indipendentemente dal fatto che ls chiama /bin/ls o /opt/gnu/bin/ls o dir o niente. IOW, which (ciò che implementazioni, IMMV) sta dando qualcosa di irrilevante
  • @St é phaneChazelas. No, no, no. So già che il mio ls è una funzione. So che la mia funzione ls sta chiamando ls da PATH. Ora which mi dice dove si trova il file. Viene visualizzato un solo caso duso: ” Cosa farebbe la mia shell con questo comando. ” Per questo caso duso which è sbagliato, corretto.Ma ci sono altri casi duso in cui (GNU) which è esattamente la cosa giusta.
  • @rudimeter, dipende da which implementazione. Alcuni ti diranno che ‘ è un alias (se hai un alias configurato o se cè un ~/.cshrc nella tua casa che ha tale alias), alcuni ti daranno un percorso ma quello sbagliato in alcune condizioni. sh -c 'command -v ls', anche se non perfetto è ancora più probabile che ti dia la risposta giusta a quel diverso requisito (ed è anche standard).

risposta

Una cosa che (dalla mia rapida lettura) sembra che Stephane non abbia “menzionato è che which ha nessuna idea sulla tabella hash del percorso della shell. Ciò ha leffetto che potrebbe restituire un risultato che non è rappresentativo di ciò che viene effettivamente eseguito, il che lo rende inefficace nel debug.

Answer

Di solito rabbrividisco quando questa domanda è consigliata a utenti ignari perché attaccare senza fondamento which non è utile per nessuno.

Se which funziona bene e fornisce la risposta corretta ad alcune attività, seguendo il moto Unix: fai una cosa, fallo bene , perché dovrebbe which essere bannato?

La domanda dovrebbe essere, quindi, quale funziona bene e fa bene un lavoro specifico?

Per prima cosa, lutilità esterna in / bin / che in Debian è uno script di shell il cui obiettivo è elencare solo gli eseguibili con il nome specificato sul percorso. Credo che which raggiunga correttamente lobiettivo prefissato. Non carica nessun alias, nessuna funzione, niente dalla shell, elenca solo i primi (o tutti) eseguibili con il nome dato sul PERCORSO. Il che significa di aver trovato un file con lo stesso nome dato è qualcosa che lutente dovrebbe capire da lei (lui) self.

Sì, altre which implementazioni possono (e di solito hanno) problemi particolari.

Risposta

Sentiamo spesso ciò che dovrebbe essere evitato. Perché? Cosa dovremmo usare invece?

Non lho mai sentito. Fornisci esempi specifici. Mi preoccuperei della tua distribuzione Linux e dei pacchetti software installati, dato che è da dove viene which!

SLES 11.4 x86-64

nella versione tcsh 6.18.01:

> which which which: shell built-in command. 

nella versione 3.2-147 di bash:

> 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 fa parte di util-linux un pacchetto standard distribuito dalla Linux Kernel Organization per luso come parte del sistema operativo Linux. Fornisce anche questi altri file

/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 

la mia util-linux è la versione 2.19. Le note di rilascio possono essere facilmente trovate indietro alla v2.13 datata (28 agosto 2007). Non sono sicuro di quale fosse il punto o lobiettivo di questo, di certo non ha avuto risposta in quella lunga cosa votata 331 volte.

Commenti

  • Notare come il la domanda non fa menzione a cosa si riferisce a Unix. Linux è solo uno dei pochi.
  • Come mostra il tuo which -v, quello GNU di ‘ che (lo stravagante uno menzionato nellaltra risposta e non è in alcun modo specifico per Linux), non util-linux che AFAIK non ha mai incluso unutilità which. util-linux 2.19 è del 2011, GNU che 2.19 è del 2008.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *