Når du ser etter stien til en kjørbar eller sjekker hva som ville skje hvis du skriver inn et kommandonavn i et Unix-skall, er det en mengde forskjellige verktøy ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
osv.).
Vi hører ofte at which
bør unngås. Hvorfor? Hva skal vi bruke i stedet?
Kommentarer
Svar
Her er alt du aldri trodde du aldri ville ønske å vite om det:
Sammendrag
For å få stinavn på en kjørbar i et Bourne-lignende skallskript (det er noen advarsler; se nedenfor):
ls=$(command -v ls)
For å finne ut om en gitt kommando eksisterer:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Ved ledeteksten fra et interaktivt Bourne-lignende skall:
type ls
The which
-kommandoen er en ødelagt arv fra C-Shell og er bedre å være alene i Bourne-lignende skjell.
Bruk tilfeller
Der «et skille mellom å lete etter den informasjonen som en del av et skript eller interaktivt på shell-ledeteksten.
Ved shell-ledeteksten er den typiske brukssaken: denne kommandoen oppfører seg merkelig, bruker jeg riktig? Hva skjedde akkurat da jeg skrev mycmd
? Kan jeg se nærmere på hva det er?
I så fall vil du vite hva skallet ditt gjør når du påkaller kommandoen uten å påkalle kommandoen.
I skallskript har det en tendens til å være ganske annerledes. I et skallskript er det ingen grunn til at du vil vite hvor eller hva en kommando er hvis alt du vil gjøre er å kjøre den. Generelt er det du vil vite banen til den kjørbare filen, slik at du kan få mer informasjon ut av den (som banen til en annen fil i forhold til den, eller lese informasjon fra innholdet i den kjørbare filen på den banen).
Interaktivt vil du kanskje vite om alle my-cmd
kommandoene som er tilgjengelige på systemet, i skript, sjelden det.
De fleste tilgjengelige verktøy (som ofte er tilfelle) er designet for å brukes interaktivt.
Historie
Litt historie først.
De tidlige Unix-skjellene til slutten av 70-tallet hadde ingen funksjoner eller aliaser. Bare den tradisjonelle oppslaget av kjørbare filer i $PATH
. csh
introduserte aliaser rundt 1978 (skjønt csh
ble først utgitt i 2BSD
, i mai 1979), og også behandlingen av en .cshrc
for brukere å tilpasse skallet (hvert skall, som csh
, leser .cshrc
selv når det ikke er interaktivt som i skript).
Mens Bourne-skallet først ble utgitt i Unix V7 tidligere i 1979, ble funksjonsstøtte bare lagt til mye senere (1984 i SVR2), og uansett, den hadde aldri noen rc
-fil (.profile
er å konfigurere miljøet ditt, ikke skallet per se ).
csh
ble mye mer populært enn Bourne-skallet som (selv om det hadde en forferdelig dårligere syntaks enn Bourne shell) tilføyde det mange mer praktiske og fine funksjoner for interaktiv bruk.
I 3BSD
(1980), en which
csh-skript ble lagt til for csh
-brukerne for å hjelpe til med å identifisere en kjørbar fil, og det er et knapt annet skript du kan finne som which
på mange kommersielle enheter i dag (som Solaris, HP / UX, AIX eller Tru64).
Dette skriptet leser brukeren» s ~/.cshrc
(som alle csh
-skript gjør med mindre de er påkalt med csh -f
), og slår opp de angitte kommandonavnene i listen over aliaser og i $path
(matrisen som csh
opprettholder basert på $PATH
).
Her går du: which
kom først for det mest populære skallet på den tiden (og csh
var fortsatt populært til midten av 90-tallet), som er den viktigste grunnen til at den ble dokumentert i bøker og fortsatt er mye brukt.
Merk at selv for en csh
-bruker, at which
csh-skript gir deg ikke nødvendigvis riktig informasjon. Det får aliasene definert i ~/.cshrc
, ikke de du kanskje har definert senere ved ledeteksten, eller for eksempel ved source
ved en annen csh
fil, og (selv om det ikke ville være en god ide), kan PATH
omdefineres i ~/.cshrc
.
Å kjøre den which
-kommandoen fra et Bourne-skall vil fremdeles slå opp aliaser som er definert i ~/.cshrc
Hvis du ikke har en fordi du ikke bruker csh
, vil det likevel sannsynligvis gi deg riktig svar.
En lignende funksjonalitet ble ikke lagt til Bourne-skallet fram til 1984 i SVR2 med type
innebygd kommando. Det faktum at den er innebygd (i motsetning til et eksternt skript) betyr at den kan gi deg riktig informasjon (til en viss grad) ettersom den har tilgang til det indre av skallet.
Den opprinnelige type
-kommandoen led av et lignende problem som which
-skriptet ved at den ikke returnerte en feilutgangsstatus hvis kommandoen ble ikke funnet. Også for kjørbare filer, i motsetning til which
, sendes den ut som ls is /bin/ls
i stedet for bare /bin/ls
som gjorde det mindre enkelt å bruke i skript.
Unix versjon 8″ s (ikke utgitt i naturen) Bourne-skall hadde det «s type
innebygd omdøpt til whatis
. Og Plan9 (den en gang etterfølgeren til Unix) skallet rc
(og dens derivater som akanga
og es
) har også whatis
.
Korn-skallet (et delsett av hvilket POSIX sh
definisjon er basert på), utviklet på midten av 80-tallet, men ikke allment tilgjengelig før 1988, la til mange av csh
-funksjonene ( linjeditor, aliaser …) på toppen av Bourne-skallet. Den la til sin egen whence
innebygd (i tillegg til type
) som tok flere alternativer (-v
for å gi type
-lignende verbose utdata, og -p
bare for å se etter kjørbare filer (ikke aliaser / funksjoner …)) .
Tilfeldig med uroen med hensyn til copyright-spørsmålene mellom AT & T og Berkeley, noen få gratis programvare skallimplementeringer kom ut på slutten av 80-tallet tidlig på 90-tallet.Alt Almquist-skallet (ash
, som erstatning for Bourne-skallet i BSD-er), implementeringen av det offentlige området av ksh
(pdksh
), bash
(sponset av FSF), zsh
kom ut mellom 1989 og 1991.
Ash, men ment å være en erstatning for Bourne-skallet, hadde ikke en type
innebygd til mye senere (i NetBSD 1.3 og FreeBSD 2.3 ), selv om den hadde hash -v
. OSF / 1 /bin/sh
hadde en type
innebygd som alltid returnerte 0 opp til OSF / 1 v3.x. bash
la ikke til en whence
men la til en -p
alternativ til type
for å skrive ut banen (type -p
vil være som whence -p
) og -a
for å rapportere alle samsvarende kommandoer. tcsh
laget which
innebygd og la til en where
kommando som fungerte som bash
» s type -a
. zsh
har dem alle.
fish
shell (2005) har en type
-kommando implementert som en funksjon.
which
csh-skript ble i mellomtiden fjernet fra NetBSD (ettersom det var innebygd i tcsh og ikke brukte mye andre skjell), og funksjonaliteten ble lagt til whereis
(når påkalt som which
, whereis
oppfører seg som which
bortsett fra at den bare ser opp kjørbare filer i iv id = «00879d7bee» I OpenBSD og FreeBSD ble which
også endret til en skrevet i C som bare ser på kommandoer i $PATH
.
Implementeringer
Det er dusinvis av implementeringer av en which
co mmog på forskjellige enheter med forskjellig syntaks og oppførsel.
På Linux (ved siden av de innebygde i tcsh
og zsh
) finner vi flere implementeringer. På nyere Debian-systemer er det for eksempel et enkelt POSIX-skallskript som ser etter kommandoer i $PATH
.
busybox
har også en which
kommando.
Det finnes en GNU
which
som sannsynligvis er den mest ekstravagante. Den prøver å utvide hva which
csh-skriptet gjorde til andre skjell: du kan fortelle det hva aliasene og funksjonene dine er, slik at det kan gi du får et bedre svar (og jeg tror noen Linux-distribusjoner setter noen globale aliaser rundt det for bash
for å gjøre det).
zsh
har et par operatorer for å utvide til banen til kjørbare filer: operatøren =
filnavnutvidelse og :c
historieutvidelsesmodifikator (her brukt på parameterutvidelse ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, i -modul lager også kommandoen hash-tabellen som commands
assosierende matrise:
$ print -r -- $commands[ls] /bin/ls
whatis
verktøyet (bortsett fra det i Unix V8 Bourne-skallet eller Plan 9 rc
/ es
) er egentlig ikke relatert, da det bare er til dokumentasjon (griper whatis-databasen, det vil si mansidesynopsis «).
whereis
var også lagt til 3BSD
samtidig som which
selv om det ble skrevet i C
, ikke csh
og brukes til å slå opp samtidig, den kjørbare, man-siden og kilden, men ikke basert på gjeldende miljø. Så igjen, det svarer på et annet behov.
Nå, på standardfronten, spesifiserer POSIX command -v
og -V
kommandoer (som tidligere var valgfrie fram til POSIX.2008). UNIX angir kommandoen type
(ikke noe alternativ). At «s all (where
, which
, whence
ikke er spesifisert i noen standard) .
Opp til en eller annen versjon var type
og command -v
valgfrie i Linux Standard Base-spesifikasjonen som forklarer hvorfor for eksempel noen gamle versjoner av posh
(skjønt basert på pdksh
som hadde begge deler) hadde ikke begge. command -v
ble også lagt til i noen Bourne-skallimplementeringer (som på Solaris).
Status i dag
Status i dag er at type
og command -v
er allestedsnærværende de Bourne-lignende skjellene (skjønt, som bemerket av @jarno, legg merke til advarselen / feilen i bash
når du ikke er i POSIX-modus eller noen etterkommere av Almquist-skallet nedenfor i kommentarer). tcsh
er det eneste skallet der du vil bruke which
(da det ikke er type
der og which
er innebygd).
I andre skjell enn tcsh
og zsh
, which
kan fortelle deg banen til den gitte kjørbare filen så lenge det ikke er noe alias eller funksjon med det samme navnet i noen av våre ~/.cshrc
, ~/.bashrc
eller en hvilken som helst shell-oppstartsfil, og du definerer ikke $PATH
i ~/.cshrc
. Hvis du har et alias eller en funksjon som er definert for det, kan det fortelle deg om det eller ikke fortelle deg det.
Hvis du vil vite omtrent alle kommandoene med et gitt navn, det er ingenting bærbart. Du ville bruke where
i tcsh
eller zsh
, type -a
i bash
eller zsh
, whence -a
i ksh93 og i andre skjell , kan du bruke type
i kombinasjon med which -a
som kan fungere.
Anbefalinger
Få stienavnet til en kjørbar
Nå, for å få stinavnet til en kjørbar i et skript, er det noen advarsler:
ls=$(command -v ls)
ville være den vanlige måten å gjøre det på.
Det er imidlertid noen få problemer:
- Det er ikke mulig å vite banen til den kjørbare filen uten å utføre den.
type
,which
,command -v
… alle bruker heuristikk for å finne veien De går gjennom$PATH
-komponentene og finner den første ikke-katalogfilen du har tillatelse til. Imidlertid depe når det gjelder å utføre kommandoen, vil mange av dem (Bourne, AT & T ksh, zsh, ash …) bare henrette dem i rekkefølgen av$PATH
tilexecve
systemanropet returnerer ikke med en feil. For eksempel hvis$PATH
inneholder/foo:/bar
og du vil utførels
, vil de først prøve å utføre/foo/ls
eller hvis det mislykkes/bar/ls
. Nå kan utførelsen av/foo/ls
mislykkes fordi du ikke har kjøringstillatelse, men også av mange andre grunner, som om den ikke er en gyldig kjørbar.command -v ls
ville rapportere/foo/ls
hvis du har kjøringstillatelse for/foo/ls
, men kjørerls
kan faktisk kjøre/bar/ls
hvis/foo/ls
ikke er en gyldig kjørbar. - hvis
foo
er en innebygd funksjon eller alias, returnerercommand -v foo
foo
. Med noen skall somash
,pdksh
ellerzsh
, kan det også returnerefoo
hvis$PATH
inkluderer den tomme strengen og det er en kjørbarfoo
-fil i gjeldende katalog. Det er noen omstendigheter der du må ta hensyn til det. Husk for eksempel at listen over innebygde programmer varierer med skallimplementeringen (for eksempel ermount
noen ganger innebygd for opptattbokssh
), og for eksempelbash
kan få funksjoner fra miljøet. - hvis
$PATH
inneholder relative banekomponenter (vanligvis.
eller den tomme strengen som begge refererer til den nåværende katalogen, men kan være hva som helst), avhengig av skallet,command -v cmd
sender kanskje ikke ut en absolutt bane. Så banen du får på det tidspunktet du kjører vil ikke lenger være gyldig etter at ducd
et annet sted. - Anekdotisk: med ksh93-skallet, hvis
/opt/ast/bin
(selv om den nøyaktige banen kan variere på forskjellige systemer tror jeg) er i deg$PATH
, ksh93 vil gjøre tilgjengelig noen ekstra innebygde (chmod
,cmp
,cat
…), mencommand -v chmod
vil returnere/opt/ast/bin/chmod
selv om den banen ikke eksisterer.
Bestemme om en kommando eksisterer
For å finne ut om en gitt kommando eksisterer standard, kan du gjøre:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Hvor man kanskje vil bruke which
(t)csh
I csh
og tcsh
har du ikke mye valg. I tcsh
, at «s fine as which
er innebygd. I csh
vil det være systemet which
-kommandoen, som kanskje ikke gjør det du vil i noen få tilfeller.
Finn kommandoer bare i noen skall
Et tilfelle der det kan være fornuftig å bruke which
er hvis du vil vite banen til en kommando, ignorerer potensialet skallinnbygginger eller funksjoner i bash
, csh
(ikke tcsh
), dash
, eller Bourne
skallskripter, det vil si skjell som ikke har whence -p
(som ksh
eller zsh
), command -ev
(som yash
), whatis -p
(rc
, akanga
) eller en innebygd which
(som tcsh
eller zsh
) på systemer der which
tilgjengelig og er ikke csh
script.
Hvis disse vilkårene er oppfylt, vil:
echo=$(which echo)
gi deg veien til den første echo
i $PATH
(unntatt i hjørnetilfeller), uansett om echo
tilfeldigvis også er et skall innebygd / alias / funksjon eller ikke.
I andre skjell foretrekker du:
- zsh :
echo==echo
ellerecho=$commands[echo]
ellerecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(pass på stier med mellomrom) - fisk :
set echo (type -fp echo)
Merk at hvis alt du vil gjøre er kjør at echo
-kommandoen, du trenger ikke å få veien, du kan bare gjøre:
env echo this is not echoed by the builtin echo
For eksempel, med tcsh
, for å forhindre at den innebygde which
blir brukt:
set Echo = "`env which echo`"
Når du trenger en ekstern kommando
Et annet tilfelle der du kanskje vil bruke which
er når du faktisk trenger en ekstern kommando. POSIX krever at alle shell-innebygde (som command
) også er tilgjengelige som eksterne kommandoer, men dessverre er det ikke tilfelle for command
på mange systemer. For eksempel er det sjelden å finne en command
-kommando på Linux-baserte operativsystemer, mens de fleste av dem har en which
kommando (skjønt forskjellige med forskjellige alternativer og oppførsel).
Tilfeller der du kanskje vil ha en ekstern kommando, vil være hvor du vil utføre en kommando uten å påkalle et POSIX-skall.
system("some command line")
, popen()
… funksjoner til C eller forskjellige språk påkaller et skall for å analysere den kommandolinjen, så system("command -v my-cmd")
fungerer i dem. Et unntak fra det ville være perl
som optimaliserer skallet hvis det ikke ser noe skallets spesialtegn (annet enn mellomrom). Det gjelder også backtick-operatøren:
$ 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
Tillegget av det :;
over tvinger perl
til å påkalle et skall der. Ved å bruke which
, trenger du ikke å bruke det trikset.
Kommentarer
- @Joe,
which
er etcsh
-skript på mange kommersielle enheter. Årsaken er historisk, at ‘ hvorfor jeg ga historien, så folk forstår hvor den kom fra, hvorfor folk ble vant til å bruke den og hvorfor det faktisk var ‘ er ingen grunn til at du skal bruke den. Og ja, noen bruker (t) csh. Ikke alle bruker Linux ennå - Etter å ha lest dette innlegget, har jeg funnet mye sammenheng for svaret, men ikke selve svaret.Hvor i dette innlegget står det faktisk hvorfor ikke å bruke
which
, i motsetning til ting du kanskje prøver å brukewhich
å gjøre, historien tilwhich
, implementeringer avwhich
, andre kommandoer for å gjøre relaterte oppgaver, eller grunner til å faktisk brukewhich
? Hvorfor er de andre kommandoene bedre ? Hva gjør de annerledes ennwhich
? Hvordan unngår de fallgruvene? Dette svaret bruker faktisk flere ord på problemene med alternativene enn problemene medwhich
. -
command
er beskrevet av POSIX. - @St é phaneChazelas Hvis jeg oppretter en ny fil med
touch /usr/bin/mytestfile
og deretter kjørercommand -v mytestfile
, det vil gi banen (menswhich mytestfile
ikke gjør det.) - @jarno, å ja, du ‘ har rett.
bash
vil slå seg til ro i en ikke-kjørbar fil hvis den ‘ ikke finner en kjørbar fil, så den ‘ s » OK » (skjønt i praksis vil man hellercommand -v
/type
returnerer en feil) som at ‘ er kommandoen den vil prøve å utføre når du kjørermytestfile
, mendash
oppførsel er ujevn, som om det ‘ er en ikke-kjørbarcmd
foran en kjørbar, returnerercommand -v
den ikke-kjørbare mens utføringcmd
ville kjøre den kjørbare (feil en er også hash). FreeBSDsh
(også basert påash
) har samme feil. zsh, yash, ksh, mksh, bash som sh er OK.
Svar
Årsakene til at man kan ikke ønsker å bruke which
har allerede blitt forklart, men her er noen eksempler på noen få systemer der which
faktisk mislykkes.
På Bourne-lignende skjell sammenligner vi utdata fra which
med utdata fra type
(type
som et skall innebygd, er det ment å være grunn sannheten, da det er skallet som forteller oss hvordan det vil påkalle en kommando).
Mange tilfeller er hjørne saker, men husk at which
/ type
ofte brukes i hjørnesaker (for å finne svaret til en uventet oppførsel som: hvorfor i all verden oppfører den kommandoen seg slik, hvilken ringer jeg til? ).
De fleste systemer, de fleste Bourne-lignende skjell: funksjoner
Det mest åpenbare tilfellet er for funksjoner:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Årsaken er at which
bare rapporterer om kjørbare filer, og noen ganger om aliaser (men ikke alltid de fra ditt skallet), ikke funksjoner.
GNU som man-siden har et ødelagt (da de glemte å sitere $@
) eksempel på hvordan man kan bruke den til å rapportere funksjoner også, men akkurat som for aliaser, fordi den ikke implementerer en skallsyntaks-parser, blir den lett lurt:
$ 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; }
De fleste systemer, de fleste Bourne-lignende skjell: innebygd
Et annet åpenbart tilfelle er innebygde eller nøkkelord, da which
å være en ekstern kommando, har ingen måte å vite hvilke innebygde skallet ditt har (og noen skall som zsh
, bash
eller ksh
kan laste innebygde dynamisk):
$ 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
(som ikke gjelder zsh
der which
er innebygd)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 og mange andre:
$ 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
Det er fordi de fleste kommersielle enheter, which
(som i den opprinnelige implementeringen på 3BSD) er et csh
skript som leser ~/.cshrc
. Aliasene den vil rapportere er de som er definert der uavhengig av aliasene du har definert for øyeblikket, og uansett skallet du faktisk bruker.
I HP / UX eller Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(Solaris- og AIX-versjonene har løst problemet ved å lagre $path
før du leser ~/.cshrc
og gjenopprette den før du ser på kommandoen (e))
$ 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
Eller:
$ 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
(selvfølgelig, hvis du er et csh
-skript, kan du ikke forvente at det fungerer med argumenter som inneholder mellomrom …)
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="
På det systemet er det et alias-definert systemomfattende som omgir GNU which
-kommandoen.
Den falske utgangen er fordi which
leser utdataene fra bash
«s alias
men vet ikke hvordan man skal analysere det riktig og bruker heuristikk (ett alias per linje, ser etter den første funnet kommandoen etter en |
, ;
, &
…)
Det verste på CentOS er at zsh
har en helt fin which
innebygd kommando, men CentOS klarte å bryte den ved å erstatte den med et ikke-fungerende alias til GNU which
.
Debian 7.0, ksh93:
(men gjelder de fleste systemer med mange skall)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
På Debian, /bin/which
er et /bin/sh
skript. I mitt tilfelle er sh
dash
men det er det samme når det «s bash
.
En usett PATH
er ikke til å deaktivere PATH
oppslag, men betyr å bruke systemet «s standard PATH som dessverre på Debian ikke er enige om (dash
og bash
har /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
har /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
har /bin:/usr/bin
, mksh
har /usr/bin:/bin
($(getconf PATH)
), execvp()
(som i env
) har :/bin:/usr/bin
(ja, ser først i gjeldende katalog!)) .
Det er grunnen til at which
gjør det galt ovenfor, siden det bruker dash
«s standard PATH
som er forskjellig fra ksh93
«s
Det er nei t bedre med GNU which
som rapporterer:
which: no which in ((null))
(interessant, det er faktisk en /usr/local/bin/which
på systemet mitt som faktisk er et akanga
skript som fulgte med akanga
(et rc
skallderivat der standard PATH
er /usr/ucb:/usr/bin:/bin:.
))
bash, hvilket som helst system:
Den Chris refererer til i sitt svar :
$ 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
Også etter å ha ringt hash
manuelt:
$ 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)
Nå er et tilfelle der which
og noen ganger type
mislykkes:
$ 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
Nå, med noen skall:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Med andre:
$ foo a/foo
Verken which
eller type
kan vite på forhånd at b/foo
ikke kan b e henrettet. Noen skall som bash
, ksh
eller yash
, når du påkaller foo
vil faktisk prøve å kjøre b/foo
og rapportere en feil, mens andre (som zsh
, ash
, csh
, Bourne
, tcsh
) vil kjøre a/foo
ved feil på execve()
systemanrop b/foo
.
Kommentarer
-
mksh
bruker faktisk noe annet for standard$PATH
: først , blir operativsystemets kompileringstidskonstant_PATH_DEFPATH
brukt (oftest på BSD-er), så brukesconfstr(_CS_PATH, …)
(POSIX), og hvis begge ikke eksisterer eller mislykkes, brukes/bin:/usr/bin:/sbin:/usr/sbin
. - I ditt første eksempel, selv om
ls
er en funksjon den brukes i gls
fra PATH. Ogwhich
er greit å fortelle deg hvilken som brukes/usr/bin/ls
eller/usr/local/bin/ls
. Jeg ser ikke ‘ t » Hvorfor ikke bruke hvilken » …. - @rudimeier, At
which ls
vil gi meg/bin/ls
uansett omls
funksjonskaller/bin/ls
eller/opt/gnu/bin/ls
ellerdir
eller ingenting. IOW,which
(det som implementeringer, IMMV) gir noe irrelevant - @St é phaneChazelas. Nei nei nei. Jeg vet allerede at
ls
er en funksjon. Jeg vet atls
-funksjonen min ringer tills
fraPATH
. Nå fortellerwhich
hvor filen er. Du ser bare ett engangsbruk: » Hva ville skjellet mitt gjort med denne kommandoen. » For dette brukstilfelletwhich
er feil, riktig.Men det er andre brukstilfeller der (GNU)which
er akkurat det rette. - @rudimeter, avhenger av
which
implementering. Noen vil fortelle deg at ‘ er et alias (hvis du har konfigurert et alias, eller hvis det er et~/.cshrc
i hjemmet ditt som har et slikt alias), noen vil gi deg en vei, men den gale under noen forhold.sh -c 'command -v ls'
, men ikke perfekt er fremdeles mer sannsynlig å gi deg riktig svar på det forskjellige kravet (og er også standard).
Svar
En ting som (fra mitt raske skum) ser ut til at Stephane ikke nevnte, er at which
har ingen anelse om skallets sti-hash-bord. Dette har den effekten at det kan gi et resultat som ikke er representativt for det som faktisk kjøres, noe som gjør det ineffektivt i feilsøking.
Svar
Jeg kryper vanligvis når dette spørsmålet anbefales til intetanende brukere fordi grunnløs bashing på which
ikke er nyttig for noen.
Hvis which
fungerer bra og gir det riktige svaret på noen oppgaver ved å følge Unix-motoen: gjør en ting, gjør det bra , hvorfor skulle which
være utestengt?
Spørsmålet bør da være, hvem som fungerer bra og gjør en bestemt jobb bra?
For det ene, det eksterne verktøyet på / bin / som i Debian er et skallskript som bare har som mål å føre kjørbare filer med gitt navn på banen. Jeg tror at which
gjør sitt tiltenkte mål riktig. Den laster ingen aliaser, ingen funksjoner, ingenting fra skallet, bare viser de første (eller alle) kjørbarhetene med gitt navn på PATH. som betyr for å ha funnet en fil med samme navn som gitt, er noe som brukeren skal finne ut av henne (ham) selv.
Ja, andre which
implementeringer kan (og vanligvis ha) spesielle problemer.
Svar
Vi hører ofte det som bør unngås. Hvorfor? Hva skal vi bruke i stedet?
Det har jeg aldri hørt. Gi spesifikke eksempler. Jeg vil bekymre deg for linux-distribusjonen og installerte programvarepakker, for så vidt kommer fra which
!
SLES 11.4 x86-64
i tcsh versjon 6.18.01:
> which which which: shell built-in command.
i bash-versjon 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
er en del av util-linux en standardpakke distribuert av Linux Kernel Organization for bruk som en del av Linux-operativsystemet. Det gir også disse andre filene
/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
min util-linux
er versjon 2.19. Versjonsmerknader kan lett bli funnet tilbake til v2.13 datert (28. august 2007). Ikke sikker på hva poenget eller målet med dette var, det ble absolutt ikke besvart den lange saken som ble oppstemt 331 ganger.
Kommentarer
- Legg merke til hvordan spørsmålet nevner ikke hva Unix det refererer til. Linux er bare en av få.
- Som din
which -v
viser, er ‘ GNU som (det ekstravagante en nevnt i det andre svaret og er på ingen måte spesifikk for Linux), ikke util-linux som AFAIK aldri inkluderte etwhich
verktøy. util-linux 2.19 er fra 2011, GNU som 2.19 er fra 2008.
which
antar en interaktiv skallkontekst. Dette spørsmålet er merket / bærbar. Så jeg tolker spørsmålet i denne sammenhengen som » hva du skal bruke i stedet forwhich
for å finne den første kjørbare filen av et gitt navn i$PATH
«. De fleste svar og grunner motwhich
tar for seg aliaser, innebygde funksjoner, som i de fleste bærbare skallskripter fra den virkelige verden bare er av akademisk interesse. Lokalt definerte aliaser er ikke ‘ t arvet når du kjører et skallskript (med mindre du kilder det med.
).csh
(ogwhich
er fremdeles etcsh
-skript på de fleste kommersielle Unices) leser~/.cshrc
når de ikke er interaktive. At ‘ er grunnen til at du ‘ merker at csh-skript vanligvis starter med#! /bin/csh -f
.which
ikke fordi det har som mål å gi deg aliasene, fordi det ‘ er ment som et verktøy for (interaktive) brukere avcsh
. POSIX-skjellbrukere harcommand -v
.(t)csh
(eller du har ikke ‘ t sinn hvis det ikke ‘ ikke gir deg riktig resultat), bruktype
ellercommand -v
i stedet . Se svarene for hvorfor .stat $(which ls)
er feil av flere grunner (mangler--
, manglende anførselstegn), ikke bare bruken avwhich
). Du ‘ brukerstat -- "$(command -v ls)"
. Det antar atls
faktisk er en kommando som finnes på filsystemet (ikke innebygd i skallet, eller aliasfunksjon).which
kan gi deg feil bane (ikke banen som skallet ditt ville utført hvis du skrev innls
) eller gi deg et alias som definert i konfigurasjonen av noen andre skjell …which
implementeringer ikke vil gi deg engangls
som vil bli funnet ved et oppslag av$PATH
(uansett hvals
kan påberope seg i skallet ditt).sh -c 'command -v ls'
, ellerzsh -c 'rpm -q --whatprovides =ls'
er mer sannsynlig å gi deg riktig svar. Poenget her er atwhich
er en ødelagt arv fracsh
.