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
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 sistemaexecve
non restituisce un errore. Ad esempio, se$PATH
contiene/foo:/bar
e desideri eseguirels
, 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 esecuzionels
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
restituiscefoo
. Con alcune shell comeash
,pdksh
ozsh
, potrebbe anche restituirefoo
se$PATH
include la stringa vuota e cè un file eseguibilefoo
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 busyboxsh
) 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 avercd
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
…), macommand -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
oecho=$commands[echo]
oecho=${${:-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 scriptcsh
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 utilizzarewhich
da fare, la cronologia diwhich
, le implementazioni diwhich
, altri comandi per eseguire attività correlate o motivi per utilizzarli effettivamentewhich
? Perché gli altri comandi sono migliori ? Che cosa fanno di diverso dawhich
? Come evitano le sue insidie? Questa risposta in realtà spende più parole sui problemi con le alternative rispetto ai problemi conwhich
. -
command
è descritto di POSIX. - @St é phaneChazelas Se creo un nuovo file da
touch /usr/bin/mytestfile
e successivamente eseguocommand -v mytestfile
, fornirà il percorso (mentrewhich 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 preferiscecommand -v
/type
restituisce un errore) poiché ‘ è il comando che tenterebbe di eseguire quando eseguimytestfile
, ma il comportamentodash
è difettoso, come se ‘ non fosse eseguibilecmd
prima di un eseguibile,command -v
restituisce quello non eseguibile mentre lesecuzione dicmd
eseguirà quello eseguibile (quello sbagliato uno è anche sottoposto ad hashing). FreeBSDsh
(anchesso basato suash
) 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
Né which
né type
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 utilizzatoconfstr(_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 gls
da PATH. Ewhich
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 chels
chiama/bin/ls
o/opt/gnu/bin/ls
odir
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 funzionels
sta chiamandols
daPATH
. Orawhich
mi dice dove si trova il file. Viene visualizzato un solo caso duso: ” Cosa farebbe la mia shell con questo comando. ” Per questo caso dusowhich
è 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.
which
presumono un contesto di shell interattivo. Questa domanda è contrassegnata / portabilità. Quindi interpreto la domanda in questo contesto come ” cosa usare invece diwhich
per trovare il primo eseguibile di un determinato nome nel$PATH
“. La maggior parte delle risposte e dei motivi contrariwhich
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.
).csh
(ewhich
è ancora uno scriptcsh
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) dicsh
. Gli utenti di shell POSIX hannocommand -v
.(t)csh
(o ‘ non ti dispiace se ‘ non ti dà il risultato corretto), utilizzatype
ocommand -v
invece . Consulta le risposte al perché .stat $(which ls)
è sbagliato per diversi motivi (manca--
, virgolette mancanti), non solo luso diwhich
). ‘ d utilizzarestat -- "$(command -v ls)"
. Ciò presuppone chels
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 inserissils
) o ti fornirà un alias come definito nella configurazione di altre shell …which
non ti darebbero nemmeno ills
che verrebbe trovato da una ricerca di$PATH
(indipendentemente da cosals
può invocare nella tua shell).sh -c 'command -v ls'
ozsh -c 'rpm -q --whatprovides =ls'
hanno maggiori probabilità di darti la risposta corretta. Il punto qui è chewhich
è uneredità spezzata dicsh
.