Når du leder efter stien til en eksekverbar eller kontrollerer, hvad der ville ske, hvis du indtaster et kommandonavn i en Unix-shell, er der en overflod af forskellige hjælpeprogrammer ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
osv.).
Vi hører ofte, at which
bør undgås. Hvorfor? Hvad skal vi bruge i stedet?
Kommentarer
Svar
Her er alt, hvad du aldrig troede, du aldrig ville have lyst til at vide om det:
Oversigt
For at få stienavn på en eksekverbar i et Bourne-lignende shell-script (der er et par advarsler; se nedenfor):
ls=$(command -v ls)
For at finde ud af om der findes en given kommando:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Ved prompt af en interaktiv Bourne-lignende shell:
type ls
The which
-kommandoen er en ødelagt arv fra C-Shell og er bedre alene i Bourne-lignende skaller.
Brug sager
Der “en sondring mellem at kigge efter disse oplysninger som en del af et script eller interaktivt på shellprompten.
Ved shellprompten er den typiske brugssag: denne kommando opfører sig underligt, bruger jeg rigtig? Hvad skete der nøjagtigt, da jeg skrev mycmd
? Kan jeg se nærmere på, hvad det er?
I så fald vil du vide, hvad din shell gør, når du påberåber sig kommandoen uden faktisk at påberåbe sig kommandoen.
I shell-scripts har det en tendens til at være helt anderledes. I et shell-script er der ingen grund til, at du vil vide, hvor eller hvad en kommando er, hvis alt hvad du vil gøre er at køre den. Generelt er det, du vil vide, stien til den eksekverbare, så du kan få mere information ud af den (som stien til en anden fil i forhold til den, eller læse oplysninger fra indholdet af den eksekverbare fil på den sti).
Interaktivt vil du måske vide om alle my-cmd
kommandoer, der er tilgængelige på systemet, i scripts, sjældent.
De fleste af de tilgængelige værktøjer (som det ofte er tilfældet) er designet til at blive brugt interaktivt.
Historie
Først en smule historie.
De tidlige Unix-skaller indtil slutningen af 70erne havde ingen funktioner eller aliaser. Kun den traditionelle sletning af eksekverbare filer i $PATH
. csh
introducerede alias omkring 1978 (skønt csh
først blev frigivet i 2BSD
, i maj 1979), og også behandlingen af en .cshrc
for brugerne til at tilpasse shell (hver shell, som csh
, læser .cshrc
selv når det ikke er interaktivt som i scripts).
Mens Bourne-skallen først blev frigivet i Unix V7 tidligere i 1979, blev funktionssupport kun tilføjet meget senere (1984 i SVR2), og alligevel havde den aldrig noget rc
fil (.profile
er til at konfigurere dit miljø, ikke skallen per se ).
csh
blev meget mere populær end Bourne-skallen, da (selvom den havde en frygtelig dårligere syntaks end Bourne shell) tilføjede en masse mere praktiske og pæne funktioner til interaktiv brug.
I 3BSD
(1980), en which
csh-script blev tilføjet til csh
-brugerne for at hjælpe med at identificere en eksekverbar, og det er et næppe andet script, du kan finde som which
på mange kommercielle enheder i dag (som Solaris, HP / UX, AIX eller Tru64).
Dette script læser brugeren” s ~/.cshrc
(som alle csh
scripts gør, medmindre de påkaldes med csh -f
) og ser de angivne kommandonavne op på listen over aliasser og i $path
(det array, som csh
opretholder baseret på $PATH
).
Here you go: which
kom først efter den mest populære shell på det tidspunkt (og csh
var stadig populær indtil midten af 90erne), hvilket er hovedårsagen til, at det blev dokumenteret i bøger og stadig bruges i vid udstrækning.
Bemærk, at selv for en csh
-bruger, at which
csh-script giver dig ikke nødvendigvis de rigtige oplysninger. Det får de aliasser, der er defineret i ~/.cshrc
, ikke dem, du måske har defineret senere ved prompten eller for eksempel ved source
ved en anden csh
fil, og (selvom det ikke ville være en god idé), kan PATH
muligvis omdefineres i ~/.cshrc
.
At køre den which
-kommando fra en Bourne-shell vil stadig slå aliasser op, der er defineret i din ~/.cshrc
hvis du ikke har en, fordi du ikke bruger csh
, ville det sandsynligvis stadig give dig det rigtige svar.
En lignende funktionalitet blev ikke tilføjet til Bourne-skallen indtil 1984 i SVR2 med type
indbygget kommando. Det faktum, at det er indbygget (i modsætning til et eksternt script) betyder, at det kan give dig de rigtige oplysninger (til en vis grad), da det har adgang til skallenes indre.
Den oprindelige type
kommando led af et lignende problem som which
scriptet, idet det ikke returnerede en status for fejlafslutning, hvis kommandoen blev ikke fundet. For eksekverbare filer, i modsætning til which
, udsender den noget som ls is /bin/ls
i stedet for bare /bin/ls
hvilket gjorde det mindre let at bruge i scripts.
Unix version 8″ s (ikke frigivet i naturen) Bourne-shell havde det “s type
indbygget omdøbt til whatis
. Og Plan9 (en gang efterfølger til Unix) skal rc
(og dens derivater som akanga
og es
) har også whatis
.
Korn-skallen (en delmængde, hvoraf POSIX sh
definition er baseret på), udviklet i midten af 80erne, men ikke bredt tilgængelig før 1988, tilføjede mange af csh
-funktionerne ( line editor, aliaser …) oven på Bourne shell. Det tilføjede sin egen whence
builtin (ud over type
), som tog flere muligheder (-v
for at give type
-lignende verbose output og -p
for kun at se efter eksekverbare filer (ikke aliaser / funktioner …)) .
Tilfældig med uroen med hensyn til ophavsretsspørgsmål mellem AT & T og Berkeley, kom der et par gratis software shellimplementeringer ud i slutningen af 80erne begyndelsen af 90erne.Hele Almquist-skallen (ash
, som erstatning for Bourne-skallen i BSDer), implementeringen af det offentlige domæne af ksh
(pdksh
), bash
(sponsoreret af FSF), zsh
kom ud mellem 1989 og 1991.
Ash, selvom det var meningen at være en erstatning for Bourne-skallen, havde ikke en type
indbygget indtil meget senere (i NetBSD 1.3 og FreeBSD 2.3 ), selvom det havde hash -v
. OSF / 1 /bin/sh
havde en type
som altid returnerede 0 op til OSF / 1 v3.x. bash
tilføjede ikke en whence
men tilføjede en -p
mulighed for at type
for at udskrive stien (type -p
ville være som whence -p
) og -a
for at rapportere alle de matchende kommandoer. tcsh
lavede which
indbygget og tilføjede en where
kommando, der fungerer som bash
” s type -a
. zsh
har dem alle.
fish
shell (2005) har en type
-kommando implementeret som en funktion.
which
csh-script blev i mellemtiden fjernet fra NetBSD (da det var indbygget i tcsh og ikke meget brug i andre skaller), og funktionaliteten blev føjet til whereis
(når påkaldt som which
, whereis
opfører sig som which
bortset fra at den kun ser på eksekverbare filer i iv id = “00879d7bee” I OpenBSD og FreeBSD blev which
også ændret til en skrevet i C, der kun ser kommandoer i $PATH
.
Implementeringer
Der er snesevis af implementeringer af en which
co mmog på forskellige enheder med forskellig syntaks og adfærd.
På Linux (ved siden af de indbyggede i tcsh
og zsh
) vi finder flere implementeringer. På for nylig Debian-systemer er det “et simpelt POSIX-shell-script, der ser efter kommandoer i $PATH
.
busybox
har også en which
kommando.
Der er en GNU
which
som sandsynligvis er den mest ekstravagante. Den forsøger at udvide, hvad which
csh-scriptet gjorde til andre skaller: du kan fortælle det, hvad dine aliaser og funktioner er, så det kan give dig et bedre svar (og jeg tror, at nogle Linux-distributioner angiver nogle globale aliaser omkring det for bash
for at gøre det).
zsh
har et par operatorer til at udvide til stien til eksekverbare filer: operatøren =
filnavnudvidelse og :c
historieudvidelsesmodifikator (her anvendt på parameterudvidelse ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, i -modul gør også kommandot hash-tabellen som commands
associativ matrix:
$ print -r -- $commands[ls] /bin/ls
whatis
-værktøjet (undtagen den i Unix V8 Bourne-skal eller Plan 9 rc
/ es
) er ikke rigtig relateret, da det kun er til dokumentation (greps whatis-databasen, det vil sige manopsidens “).
whereis
var også tilføjet i 3BSD
på samme tid som which
selvom det blev skrevet i C
, ikke csh
og bruges til at slå op på samme tid, den eksekverbare, man-side og kilde, men ikke baseret på det aktuelle miljø. Så igen svarer det på et andet behov.
Nu på standardfronten specificerer POSIX command -v
og -V
kommandoer (som tidligere var valgfri indtil POSIX.2008). UNIX angiver kommandoen type
(ingen mulighed). At “s alle (where
, which
, whence
er ikke angivet i nogen standard) .
Op til en eller anden version var type
og command -v
valgfri i Linux Standard Base-specifikationen, hvilket forklarer hvorfor nogle gamle versioner af posh
(dog baseret på pdksh
, som begge havde begge), havde heller ikke nogen. command -v
blev også føjet til nogle Bourne shell-implementeringer (som på Solaris).
Status i dag
Status i dag er, at type
og command -v
er allestedsnærværende de Bourne-lignende skaller (dog som bemærket af @jarno skal du bemærke advarslen / bugten i bash
når de ikke er i POSIX-tilstand eller nogle efterkommere af Almquist-skallen nedenfor i kommentarer). tcsh
er den eneste skal, hvor du vil bruge which
(da der ikke er noget type
der og which
er indbygget).
I andre skaller end tcsh
og zsh
, which
fortæller dig muligvis stien til den givne eksekverbare, så længe der ikke er noget alias eller funktion med det samme navn i nogen af vores ~/.cshrc
, ~/.bashrc
eller en hvilken som helst shell-startfil, og du definerer ikke $PATH
i din ~/.cshrc
. Hvis du har defineret et alias eller en funktion til det, fortæller det dig måske ikke eller fortæller dig den forkerte ting.
Hvis du vil vide det om alle kommandoerne med et givet navn er der intet bærbart. Du ville bruge where
i tcsh
eller zsh
, type -a
i bash
eller zsh
, whence -a
i ksh93 og i andre skaller , kan du bruge type
i kombination med which -a
som muligvis fungerer.
Anbefalinger
At få stienavnet til en eksekverbar
For at få stienavnet til en eksekverbar i et script er der et par advarsler:
ls=$(command -v ls)
ville være den standard måde at gøre det på.
Der er dog nogle få problemer:
- Det er ikke muligt at kende stien til den eksekverbare uden at udføre den.
type
,which
,command -v
… alle bruger heuristik til at finde ud af stien De løber gennem$PATH
-komponenterne og finder den første ikke-biblioteksfil, som du har tilladelse til. Dog depe nding på skallen, når det kommer til udførelse af kommandoen, vil mange af dem (Bourne, AT & T ksh, zsh, ash …) bare udføre dem i rækkefølgen af$PATH
indtilexecve
systemopkald vender ikke tilbage med en fejl. For eksempel, hvis$PATH
indeholder/foo:/bar
, og du vil udførels
, prøver de først at udføre/foo/ls
eller hvis det mislykkes/bar/ls
. Nu kan udførelse af/foo/ls
muligvis mislykkes, fordi du ikke har eksekveringstilladelse, men også af mange andre grunde, da det ikke er en gyldig eksekverbar.command -v ls
rapporterer/foo/ls
hvis du har eksekveringstilladelse til/foo/ls
, men kørerls
kører muligvis/bar/ls
hvis/foo/ls
ikke er en gyldig eksekverbar fil. - hvis
foo
er en indbygget funktion eller et alias, returnerercommand -v foo
foo
. Med nogle skaller somash
,pdksh
ellerzsh
, kan det også returnerefoo
hvis$PATH
inkluderer den tomme streng, og der er en eksekverbarfoo
-fil i den aktuelle mappe. Der er nogle omstændigheder, hvor du muligvis skal tage det i betragtning. Husk for eksempel, at listen over indbyggede varierer med implementeringen af shell (for eksempel ermount
undertiden indbygget til optaget bokssh
), og f.eks.bash
kan få funktioner fra miljøet. - hvis
$PATH
indeholder relative stykomponenter (typisk.
eller den tomme streng, som begge henviser til den aktuelle mappe, men som muligvis kan være hvad som helst), afhængigt af skallen,command -v cmd
udsender muligvis ikke en absolut sti. Så den sti, du opnår på det tidspunkt, du kører er ikke længere gyldig, efter at ducd
et andet sted. - Anekdotisk: med ksh93-skallen, hvis
/opt/ast/bin
(selvom den nøjagtige sti kan variere på forskellige systemer, tror jeg) er i dig$PATH
, ksh93 vil stille et par ekstra indbyggede til rådighed (chmod
,cmp
,cat
…), mencommand -v chmod
returnerer/opt/ast/bin/chmod
, selvom stien ikke findes.
Bestemmelse af, om der findes en kommando
For at finde ud af, om en given kommando eksisterer som standard, kan du gø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 måske vil bruge which
(t)csh
I csh
og tcsh
har du ikke meget valg. I tcsh
er det “s fint som which
er indbygget. I csh
er det kommandoen which
, som muligvis ikke gør hvad du vil i nogle få tilfælde.
Find kun kommandoer i nogle skaller
Et tilfælde, hvor det kan være fornuftigt at bruge which
er, hvis du vil kende stien til en kommando og ignorere potentialet shell-indbyggede funktioner i bash
, csh
(ikke tcsh
), dash
eller Bourne
shell-scripts, det vil sige skaller, der ikke har whence -p
= “cd104fd905”>
ellerzsh
),command -ev
(somyash
),whatis -p
(rc
,akanga
) eller en indbyggetwhich
(somtcsh
ellerzsh
) på systemer, hvorwhich
tilgængelig og er ikkecsh
script.
Hvis disse betingelser er opfyldt, vil:
echo=$(which echo)
give dig stien til den første echo
i $PATH
(undtagen i hjørnetilfælde), uanset om echo
også tilfældigvis er en shell indbygget / alias / funktion eller ej.
I andre skaller foretrækker 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`
(pas på stier med mellemrum) - fisk :
set echo (type -fp echo)
Bemærk, at hvis alt hvad du vil gøre er kør at echo
kommando, du behøver ikke at få sin sti, du kan bare gøre:
env echo this is not echoed by the builtin echo
For eksempel med tcsh
for at forhindre, at det indbyggede which
bruges:
set Echo = "`env which echo`"
Når du har brug for en ekstern kommando
Et andet tilfælde, hvor du måske vil bruge which
, er når du faktisk har brug for en ekstern kommando. POSIX kræver, at alle shell-indbyggede (som command
) også er tilgængelige som eksterne kommandoer, men desværre er det ikke tilfældet for command
på mange systemer. For eksempel er det sjældent at finde en command
kommando på Linux-baserede operativsystemer, mens de fleste af dem har en which
kommando (dog forskellige med forskellige indstillinger og adfærd).
Tilfælde, hvor du muligvis vil have en ekstern kommando, vil være overalt, hvor du udfører en kommando uden at påkalde en POSIX-shell.
system("some command line")
, popen()
… funktioner på C eller forskellige sprog påkalder en shell for at analysere kommandolinjen, så system("command -v my-cmd")
arbejder i dem. En undtagelse derfra ville være perl
, som optimerer skallen, hvis den ikke ser noget shell-specialtegn (bortset fra mellemrum). Det gælder også dens backtick-operatør:
$ 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
Tilføjelsen af den :;
ovenfor tvinger perl
til at påkalde en shell der. Ved at bruge which
behøver du ikke bruge det trick.
Kommentarer
- @Joe,
which
er etcsh
script på mange kommercielle enheder. Årsagen er historisk, at ‘ hvorfor jeg gav historien, så folk forstår, hvor den kom fra, hvorfor folk blev vant til at bruge den, og hvorfor der faktisk ‘ er ingen grund til at bruge det. Og ja, nogle mennesker bruger (t) csh. Ikke alle bruger Linux endnu - Efter at have læst dette indlæg har jeg fundet en masse kontekst til svaret, men ikke selve svaret.Hvor i dette indlæg siger det faktisk ikke at bruge
which
i modsætning til ting, du måske prøver at brugewhich
at gøre, historien omwhich
, implementeringer afwhich
, andre kommandoer til at udføre relaterede opgaver eller grunde til faktisk at brugewhich
? Hvorfor er de andre kommandoer bedre ? Hvad gør de anderledes endwhich
? Hvordan undgår de faldgruber? Dette svar bruger faktisk flere ord på problemerne med alternativerne end problemerne medwhich
. -
command
er beskrevet af POSIX. - @St é phaneChazelas Hvis jeg opretter en ny fil med
touch /usr/bin/mytestfile
og kør dereftercommand -v mytestfile
, det giver stien (hvorimodwhich mytestfile
ikke). - @jarno, åh ja, du ‘ har ret.
bash
vil slå sig ned på en ikke-eksekverbar fil, hvis den ‘ ikke kan finde en eksekverbar fil, så den ‘ s ” OK ” (selvom man i praksis hellere vilcommand -v
/type
returnerer en fejl) som at ‘ er kommandoen, den vil prøve at udføre, når du kørermytestfile
, mendash
adfærd er ujævn, som om der ‘ er en ikke-eksekverbarcmd
foran en eksekverbar encommand -v
returnerer den ikke-eksekverbare, mens udførelse afcmd
ville udføre den eksekverbare (den forkerte man er også hash). FreeBSDsh
(også baseret påash
) har den samme fejl. zsh, yash, ksh, mksh, bash som sh er OK.
Svar
Årsagerne til, at man kan ikke ønsker at bruge which
er allerede blevet forklaret, men her er et par eksempler på et par systemer, hvor which
faktisk fejler.
På Bourne-lignende skaller sammenligner vi output fra which
med output fra type
(type
er en shell-indbygget, menes det at være grundens sandhed, da det er skallen, der fortæller os, hvordan det vil påberåbe sig en kommando).
Mange tilfælde er hjørne sager, men husk at which
/ type
ofte bruges i hjørnesager (for at finde svaret til en uventet opførsel som: hvorfor i alverden opfører den kommando sig sådan, hvilken kalder jeg på? ).
De fleste systemer, de fleste Bourne-lignende skaller: funktioner
Det mest oplagte tilfælde er for funktioner:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Årsagen er, at which
kun rapporterer om eksekverbare filer og nogle gange om aliaser (dog ikke altid dem fra din shell), ikke om funktioner.
Den GNU, som man-siden har brudt (da de glemte at citere $@
) eksempel på, hvordan man også bruger den til at rapportere funktioner, men ligesom for aliaser, fordi den ikke implementerer en shell-syntaks-parser, narre den let:
$ 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, mest Bourne-lignende skaller: builtins
Et andet indlysende tilfælde er indbyggede eller nøgleord, da which
at være en ekstern kommando ikke har nogen måde at vide, hvilke indbyggede din shell har (og nogle skaller som zsh
, bash
eller ksh
kan indlæse buildins 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
(det gælder ikke for zsh
hvor which
er indbygget)
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
Dette skyldes, at de fleste kommercielle enheder which
(som i den oprindelige implementering på 3BSD) er et csh
script, der læser ~/.cshrc
. De aliasser, den rapporterer, er dem, der er defineret der uanset de aliasser, du i øjeblikket har defineret, og uanset den shell, du rent faktisk bruger.
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-versionerne har løst problemet ved at gemme $path
før du læser ~/.cshrc
og gendanne det, før du slår kommandoen (e) op)
$ 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, da du er et csh
script, kan du ikke forvente, at det fungerer med argumenter, der indeholder mellemrum …)
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å dette system er der et alias-defineret system-bredt, der omslutter GNU which
-kommandoen.
Den falske output skyldes, at which
læser output fra bash
“s alias
men ved ikke, hvordan man analyserer det ordentligt og bruger heuristik (et alias pr. linje, ser efter den første fundne kommando efter en |
, ;
, &
…)
Det værste ved CentOS er, at zsh
har en perfekt fin which
indbygget kommando, men CentOS formåede at bryde den ved at erstatte den med et ikke-fungerende alias til GNU which
.
Debian 7.0, ksh93:
(dog gælder de fleste systemer med mange skaller)
$ 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
script. I mit tilfælde er sh
dash
men det er det samme, når det “s bash
.
En ikke-indstillet PATH
er ikke til at deaktivere PATH
opslag, men betyder at bruge systemet “s standard PATH som desværre på Debian ikke er enig i (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 den aktuelle mappe!)) .
Derfor får which
det forkert ovenfor, da det bruger dash
“s standard PATH
som er forskellig fra ksh93
“s
Det er nej t bedre med GNU which
som rapporterer:
which: no which in ((null))
(interessant er der faktisk en /usr/local/bin/which
på mit system, som faktisk er et akanga
script, der fulgte med akanga
(et rc
shell-derivat, hvor standard PATH
er /usr/ucb:/usr/bin:/bin:.
))
bash, ethvert system:
Den Chris henviser til i sit 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å efter at have ringet til 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)
Nu er det tilfældet, hvor which
og undertiden 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
Nu med nogle skaller:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Med andre:
$ foo a/foo
Hverken which
eller type
kan på forhånd vide, at b/foo
ikke kan b e udført. Nogle skaller som bash
, ksh
eller yash
, når de påkalder foo
vil faktisk prøve at køre b/foo
og rapportere en fejl, mens andre (som zsh
, ash
, csh
, Bourne
, tcsh
) kører a/foo
ved fejl i execve()
systemkald b/foo
.
Kommentarer
-
mksh
bruger faktisk noget andet til standard$PATH
: først , bruges operativsystemets kompileringstidskonstant_PATH_DEFPATH
(oftest på BSDer), derefter anvendesconfstr(_CS_PATH, …)
(POSIX), og hvis begge ikke findes eller mislykkes, bruges/bin:/usr/bin:/sbin:/usr/sbin
. - I dit 1. eksempel, selvom
ls
er en funktion, den bruges i gls
fra PATH. Ogwhich
er fint at fortælle dig, hvilken der bruges/usr/bin/ls
eller/usr/local/bin/ls
. Jeg ser ikke ‘ ” Hvorfor ikke bruge hvilken ” …. - @rudimeier, At
which ls
giver mig/bin/ls
uanset omls
funktion kalder/bin/ls
eller/opt/gnu/bin/ls
ellerdir
eller slet ingenting. IOW,which
(det, som implementeringer, IMMV) giver noget irrelevant - @St é phaneChazelas. Nej Nej Nej. Jeg ved allerede, at min
ls
er en funktion. Jeg ved at minls
funktion kalderls
fraPATH
. Nu fortællerwhich
mig, hvor filen er. Du ser kun en enkelt brugssag: ” Hvad ville min shell gøre med denne kommando. ” Til denne brugssagwhich
er forkert, korrekt.Men der er andre brugstilfælde, hvor (GNU)which
er nøjagtigt den rigtige ting. - @rudimeter afhænger af
which
implementering. Nogle vil fortælle dig, at det ‘ er et alias (hvis du har et alias konfigureret, eller hvis der er et~/.cshrc
i dit hjem, der har sådan et alias), nogle vil give dig en vej, men den forkerte under visse betingelser.sh -c 'command -v ls'
, selvom det ikke er perfekt, er det stadig mere sandsynligt, at det giver dig det rigtige svar på det forskellige krav (og er også standard).
Svar
En ting, som (fra mit hurtige skum) ser ud til, at Stephane ikke nævnte, er at which
har ingen idé om din shell “sti-hash-tabel. Dette har den virkning, at det muligvis returnerer et resultat, der ikke er repræsentativt for det, der faktisk køres, hvilket gør det ineffektivt i fejlfinding.
Svar
Jeg krymper normalt, når dette spørgsmål anbefales til intetanende brugere, fordi grundløs bashing på which
ikke er nyttig for nogen.
Hvis which
fungerer godt og giver det rigtige svar på en eller anden opgave ved at følge Unix-motoen: gør en ting, gør det godt hvorfor skal which
være forbudt?
Spørgsmålet skal så være, hvilken der fungerer godt og gør et specifikt job godt?
For det ene er det eksterne værktøj ved / bin / hvilket i Debian er et shell-script, hvis mål kun er at angive eksekverbare filer med det givne navn på stien. Jeg tror, at which
gør sit tilsigtede mål korrekt. Den indlæser ingen aliaser, ingen funktioner, intet fra skallen, lister bare de første (eller alle) eksekverbare filer af det givne navn på PATH. betyder for at have fundet en fil med samme navn som givet er noget, som brugeren skal finde ud af af hende (ham) selv.
Ja, andre which
implementeringer kan (og har normalt) særlige problemer.
Svar
Vi hører ofte, hvad der skal undgås. Hvorfor? Hvad skal vi bruge i stedet?
Det har jeg aldrig hørt. Angiv specifikke eksempler. Jeg ville bekymre mig om din linux-distribution og installerede softwarepakker, for det er det sted, hvor which
kommer fra!
SLES 11.4 x86-64
i tcsh version 6.18.01:
> which which which: shell built-in command.
i bash-version 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 af util-linux en standardpakke distribueret af Linux Kernel Organization til brug som en del af Linux-operativsystemet. Det giver også disse andre filer
/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 version 2.19. Udgivelsesnoter kan let findes tilbage til v2.13 dateret (28. august 2007). Ikke sikker på hvad pointen eller målet med dette var, det blev bestemt ikke besvaret i den lange ting, der blev opstemt 331 gange.
Kommentarer
- Bemærk hvordan spørgsmål nævnes ikke, hvad Unix det henviser til. Linux er blot et af få.
- Som din
which -v
viser, at ‘ s GNU som (det ekstravagante en nævnt i det andet svar og er på ingen måde specifik for Linux), ikke util-linux, som AFAIK aldrig inkluderede etwhich
-værktøj. util-linux 2.19 er fra 2011, GNU som 2.19 er fra 2008.
which
antager en interaktiv shell-kontekst. Dette spørgsmål er tagget / bærbarhed. Så jeg fortolker spørgsmålet i denne sammenhæng som ” hvad man skal bruge i stedet forwhich
til at finde den første eksekverbare fil af et givet navn i$PATH
“. De fleste svar og grunde imodwhich
beskæftiger sig med aliaser, indbyggede funktioner og funktioner, som i de fleste bærbare shell-scripts fra den virkelige verden bare er af akademisk interesse. Lokalt definerede aliasser arves ikke ‘ t, når du kører et shell-script (medmindre du kilder det til.
).csh
(ogwhich
er stadig etcsh
script på de fleste kommercielle Unices) læser~/.cshrc
når de ikke er interaktive. At ‘ hvorfor du ‘ bemærker, at csh-scripts normalt starter med#! /bin/csh -f
.which
ikke fordi det sigter at give dig aliaserne, fordi det ‘ er ment som et værktøj til (interaktive) brugere afcsh
. Brugere af POSIX-skaller harcommand -v
.(t)csh
(eller hvis du ikke ‘ ikke har noget imod det, hvis det ikke ‘ ikke giver dig det rigtige resultat), brugtype
ellercommand -v
i stedet . Se svarene til hvorfor .stat $(which ls)
er forkert af flere årsager (mangler--
, manglende anførselstegn), ikke kun brugen afwhich
). Du ‘ brugerstat -- "$(command -v ls)"
. Det antager, atls
faktisk er en kommando, der findes på filsystemet (ikke en indbygget i din shell eller aliasfunktion).which
kan give dig den forkerte sti (ikke den sti, som din shell ville udføre, hvis du indtastedels
) eller give dig et alias som defineret i konfigurationen af nogle andre skaller …which
implementeringer ikke ville give dig engangls
der ville blive fundet ved et opslag af$PATH
(uanset hvadls
kan påberåbe sig i din skal).sh -c 'command -v ls'
ellerzsh -c 'rpm -q --whatprovides =ls'
er mere tilbøjelige til at give dig det rigtige svar. Pointen her er, atwhich
er en brudt arv fracsh
.