Při hledání cesty ke spustitelnému souboru nebo kontrole toho, co by se stalo, kdybyste zadali název příkazu do prostředí Unix, existuje spousta různých nástrojů ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
atd.).
Často slyšíme, že which
je třeba se vyhnout. Proč? Co bychom místo toho měli použít?
Komentáře
Odpověď
Zde je vše, o čem jste si nikdy nemysleli, že o něm nikdy nebudete chtít vědět:
Shrnutí
Chcete-li získat cesta ke spustitelnému souboru ve skriptu prostředí typu Bourne (existuje několik upozornění; viz níže):
ls=$(command -v ls)
Zjištění, zda daný příkaz existuje:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Na výzvu interaktivního prostředí podobného Bourneovi:
type ls
Příkaz which
je rozbitým dědictvím C-Shell a měl by být ponechán sám v Bourneových granátech.
Použít případy
Tam „Rozdíl mezi hledáním těchto informací jako součásti skriptu nebo interaktivním zobrazením příkazového řádku.
Typický příklad použití příkazového řádku je: tento příkaz se chová divně, používám správně? Co přesně se stalo, když jsem napsal mycmd
? Mohu se dále podívat na to, co to je?
V takovém případě chcete vědět, co váš shell dělá, když vyvoláte příkaz, aniž byste jej skutečně vyvolali.
V shell skriptech to má tendenci být úplně jiné. Ve skořápkovém skriptu není důvod, proč byste chtěli vědět, kde nebo co je příkaz, pokud ho chcete spustit. Obecně platí, že chcete zjistit cestu spustitelného souboru, abyste z něj mohli získat více informací (například relativní cestu k jinému souboru nebo číst informace z obsahu spustitelného souboru na této cestě).
Interaktivně můžete chtít vědět o všech my-cmd
příkazech dostupných v systému, ve skriptech, zřídka.
Většina dostupných nástrojů (jak se často stává) byla navržena pro interaktivní použití.
Historie
Nejprve trochu historie.
Brzy unixové granáty až do konce 70. let neměly žádné funkce ani aliasy. Pouze tradiční vyhledávání spustitelných souborů v $PATH
. csh
zavedené aliasy kolem roku 1978 (ačkoli csh
byl poprvé vydán v 2BSD
, v květnu 1979) a také zpracování .cshrc
, aby si uživatelé mohli shell přizpůsobit (každý shell jako csh
, čte .cshrc
i když není interaktivní jako ve skriptech).
Zatímco prostředí Bourne bylo poprvé vydáno v Unixu V7 dříve v roce 1979, podpora funkcí byla přidána jen mnohem později (1984 v SVR2) a každopádně nikdy neměl nějaký rc
soubor (.profile
je konfigurace vašeho prostředí, nikoli shellu per se ).
csh
je mnohem populárnější než prostředí Bourne jako (i když měl strašně horší syntaxi než Bourne shell) přidával mnoho pohodlnějších a příjemnějších funkcí pro interaktivní použití.
V 3BSD
(1980), which
byl přidán skript csh , který pomáhá identifikovat spustitelný soubor, a je to jen těžko odlišný skript, který najdete jakowhich
v dnešní době na mnoha komerčních Unices (jako Solaris, HP / UX, AIX nebo Tru64).
Tento skript čte uživatelský ~/.cshrc
(jako všechny csh
skripty, pokud nejsou vyvolány pomocí csh -f
) a vyhledá zadané názvy příkazů v seznamu aliasů a v $path
(pole, které csh
udržuje na základě $PATH
).
Tady to je: which
byl v té době nejpopulárnějším shellem první (a csh
byl stále populární až do poloviny 90. let), což je hlavní důvod, proč byl dokumentován v knihách a je stále široce používán.
Upozorňujeme, že i pro uživatele csh
je which
skript csh vám nemusí nutně poskytnout správné informace. Získá aliasy definované v ~/.cshrc
, nikoli ty, které jste mohli definovat později na výzvu nebo například source
ing dalším csh
soubor a (i když by to nebyl dobrý nápad), PATH
může být předefinováno v ~/.cshrc
.
Spuštěním příkazu which
z prostředí Bourne by se stále vyhledávaly aliasy definované ve vašem ~/.cshrc
, ale pokud žádný nemáte, protože nepoužíváte csh
, pravděpodobně byste dostali správnou odpověď.
Podobná funkce nebyla přidána do prostředí Bourne do roku 1984 v SVR2 pomocí integrovaného příkazu type
. Skutečnost, že je integrována (na rozdíl od externího skriptu), znamená, že vám může poskytnout správné informace (do určité míry), protože má přístup k vnitřním částem prostředí.
Počáteční příkaz type
utrpěl podobný problém jako skript which
, protože nevrátil stav ukončení selhání, pokud příkaz nebyl nalezen. Také pro spustitelné soubory, na rozdíl od which
, vydává něco jako ls is /bin/ls
místo pouze /bin/ls
což usnadnilo použití ve skriptech.
Unix verze 8 (nevydaný ve volné přírodě) Bourne shell jej měl“ s type
builtin přejmenován na whatis
. A plánek Plan9 (bývalý nástupce Unixu) rc
(a jeho deriváty jako akanga
a es
) mají také whatis
.
Korn shell (podmnožina, která Definice POSIX sh
je založena), který byl vyvinut v polovině 80. let, ale nebyl široce dostupný před rokem 1988, přidal mnoho funkcí csh
( line editor, aliasy …) v horní části Bourne shellu. Přidal vlastní whence
vestavěný (kromě type
), který vzal několik možností (-v
poskytnout podrobný výstup podobný type
a -p
hledat pouze spustitelné soubory (nikoli aliasy / funkce …)) .
Shodou okolností nepokoje ohledně problémů s autorskými právy mezi AT & T a Berkeley, přišlo několik svobodných softwarových implementací prostředí. na konci 80. let počátkem 90. let.Celý Almquistův shell (ash
, který má být nahrazen Bourneovým shellem v BSD), implementace public domain ksh
(pdksh
), bash
(sponzorovaný FSF), zsh
vyšel v letech 1989 až 1991.
Ash, i když měl být náhradou za shell Bourne, neměl type
zabudovaný až mnohem později (v NetBSD 1.3 a FreeBSD 2.3 ), ačkoli měl hash -v
. OSF / 1 /bin/sh
měl type
zabudovaný, který vždy vrátil 0 až OSF / 1 v3.x. bash
nepřidal whence
, ale přidal -p
možnost type
vytisknout cestu (type -p
by vypadalo jako whence -p
) a -a
k nahlášení všech odpovídajících příkazů. tcsh
vytvořil which
vestavěný a přidal příkaz where
fungující jako bash
“ s type -a
. zsh
má všechny.
fish
shell (2005) má type
implementovaný jako funkce.
which
skript csh byl mezitím odstraněn z NetBSD (protože byl zabudován do tcsh a není příliš použitelný v jiných skořápkách) a funkce přidána do whereis
(při vyvolání jako which
, whereis
se chová jako which
kromě toho, že vyhledá pouze spustitelné soubory v $PATH
). V OpenBSD a FreeBSD byl which
také změněn na jeden napsaný v C, který vyhledává příkazy pouze v $PATH
.
Implementace
Existují desítky implementací which
co mmand na různých Unices s odlišnou syntaxí a chováním.
Na Linuxu (kromě těch vestavěných v tcsh
a zsh
) najdeme několik implementací. Například na nedávných systémech Debian je to jednoduchý skript POSIXu, který hledá příkazy v $PATH
.
busybox
má také which
příkaz.
Existuje GNU
which
což je pravděpodobně ten nejextravagantnější. Pokouší se rozšířit to, co skript which
csh udělal na jiné skořápky: můžete mu říci, jaké jsou vaše aliasy a funkce, aby mohl poskytnout máte lepší odpověď (a domnívám se, že některé distribuce Linuxu nastavují kolem toho nějaké globální aliasy pro bash
).
zsh
má několik operátorů , které se rozšíří na cestu spustitelných souborů: =
expanze názvu souboru a :c
modifikátor rozšíření historie (zde použito pro rozšíření parametrů ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
v také vytváří tabulku hash příkazu jako commands
asociativní pole:
$ print -r -- $commands[ls] /bin/ls
Obslužný program whatis
(kromě toho v prostředí Unix V8 Bourne shell nebo Plan 9 rc
/ es
) ve skutečnosti nesouvisí, protože je pouze pro dokumentaci (greps the whatis database, that is the man page synopsis „).
whereis
byl také přidáno do 3BSD
současně s which
ačkoli to bylo napsáno v C
, ne csh
a slouží k vyhledání současně spustitelného souboru, manuálové stránky a zdroje, ale není založeno na aktuálním prostředí. To opět odpovídá jiné potřebě.
Nyní, na standardní frontě, POSIX specifikuje command -v
a -V
příkazy (které byly do POSIX.2008 volitelné). UNIX určuje příkaz type
(bez možnosti). To vše (where
, which
, whence
nejsou specifikovány v žádném standardu) .
Až do určité verze byly type
a command -v
ve specifikaci Linux Standard Base volitelné, což vysvětluje, proč instance některé staré verze posh
(i když založené na pdksh
, které měly obě) neměly ani jednu. command -v
byl také přidán do některých implementací prostředí Bourne (například na systému Solaris).
Stav dnes
Dnešní stav je, že type
a command -v
jsou ve všech případech všudypřítomné bourneovské mušle (jak však poznamenal @jarno, všimněte si upozornění / chyby v bash
, pokud nejste v režimu POSIX nebo někteří potomci almquistského shellu níže v komentářích). tcsh
je jediný shell, ve kterém byste chtěli použít which
(protože neexistuje type
there and which
is builtin).
V jiných skořápkách než tcsh
a zsh
, which
vám může sdělit cestu daného spustitelného souboru, pokud v žádném z našich ~/.cshrc
, ~/.bashrc
nebo jakýkoli spouštěcí soubor prostředí a ve svém iv id „nedefinujete $PATH
= „c92e1ab12d“> . Pokud pro něj máte definován alias nebo funkci, může nebo nemusí vám o něm říci nebo vám řekne špatnou věc.
Pokud chcete vědět o všech příkazech pod křestním jménem není nic přenosného. Použijete where
v tcsh
nebo zsh
, type -a
v bash
nebo zsh
, whence -a
v ksh93 a v jiných skořápkách , můžete použít type
v kombinaci s which -a
, které mohou fungovat.
Doporučení
Získání cesty ke spustitelnému souboru
Chcete-li získat cestu ke spustitelnému souboru ve skriptu, je zde několik upozornění:
ls=$(command -v ls)
by to byl standardní způsob, jak to udělat.
Existuje však několik problémů:
- Není možné znát cestu spustitelného souboru bez jeho provedení. the
type
,which
,command -v
… všichni používají heuristiku k nalezení cesty Procházejí komponenty$PATH
a najdou první soubor, který není adresář, ke kterému máte oprávnění ke spuštění. Depe nding na shellu, pokud jde o provedení příkazu, mnoho z nich (Bourne, AT & T ksh, zsh, ash …) je provede pouze v pořadí$PATH
dokud seexecve
systémové volání nevrátí s chybou. Pokud například$PATH
obsahuje/foo:/bar
a chcete spustitls
, nejprve se pokusí provést/foo/ls
nebo pokud se to nepodaří/bar/ls
. Nyní může spuštění/foo/ls
selhat, protože nemáte oprávnění k provádění, ale také z mnoha dalších důvodů, například není platný spustitelný soubor.command -v ls
by nahlásil/foo/ls
, pokud máte oprávnění ke spuštění pro/foo/ls
, ale běžíls
může běžet/bar/ls
, pokud/foo/ls
není platný spustitelný soubor. - pokud
foo
je vestavěná funkce nebo alias,command -v foo
vrátífoo
. S některými skořápkami jakoash
,pdksh
nebozsh
může také vrátitfoo
pokud$PATH
obsahuje prázdný řetězec a v aktuálním adresáři je spustitelnýfoo
soubor. Existují okolnosti, za kterých to budete muset vzít v úvahu. Mějte na paměti, že například seznam vestavěných modulů se liší podle implementace prostředí (napříkladmount
je pro busybox někdy zabudovánsh
) a napříkladbash
může získávat funkce z prostředí. - pokud
$PATH
obsahuje relativní komponenty cesty (obvykle.
nebo prázdný řetězec, který oba odkazují na aktuální adresář, ale může to být cokoli), v závislosti na prostředí,command -v cmd
nemusí vydávat absolutní cestu. Cesta, kterou získáte při spuštění již nebude platit, kdyžcd
někde jinde. - Neoficiální: s prostředím ksh93, pokud
/opt/ast/bin
(i když se tato přesná cesta může v různých systémech lišit) je ve vás$PATH
, ksh93 zpřístupní několik dalších vestavěných funkcí (chmod
,cmp
,cat
…), alecommand -v chmod
vrátí/opt/ast/bin/chmod
, i když tato cesta neexistuje.
Určení, zda příkaz existuje
Chcete-li zjistit, zda daný příkaz existuje standardně, můžete provést:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Kde by někdo mohl chtít použít which
(t)csh
V csh
a tcsh
nemáte moc na výběr. V tcsh
„Je v pořádku, protože which
je integrován. V csh
to bude systémový which
příkaz, který v několika případech nemusí dělat to, co chcete.
Najít příkazy pouze v některých skořápkách
Případ, kdy by mohlo mít smysl použít which
, je, pokud chcete znát cestu příkazu, ignorovat potenciál vestavěné prostředí nebo funkce v bash
, csh
(ne tcsh
), dash
nebo Bourne
shell skripty, tj. Skořápky, které nemají whence -p
(jako ksh
nebo zsh
), command -ev
(jako yash
), whatis -p
(rc
, akanga
) nebo vestavěný which
(jako tcsh
nebo zsh
) v systémech, kde je which
k dispozici a nejedná se o csh
skript.
Pokud jsou tyto podmínky splněny, pak:
echo=$(which echo)
vám poskytne cestu k prvnímu echo
v $PATH
(kromě rohových případů), bez ohledu na to, zda echo
je také shell vestavěný / alias / funkce nebo ne.
V jiných skořápkách dáváte přednost:
- zsh :
echo==echo
neboecho=$commands[echo]
neboecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(pozor na cesty s mezerami) - ryby :
set echo (type -fp echo)
Všimněte si, že pokud chcete spustit ten echo
příkaz, jeho cestu nemusíš najít, stačí:
env echo this is not echoed by the builtin echo
Například pomocí tcsh
zabránit použití integrovaného which
:
set Echo = "`env which echo`"
Když potřebujete externí příkaz
Další případ, kdy budete chtít použít which
, je ten, kdy skutečně potřebujete externí příkaz. POSIX vyžaduje, aby všechny vestavěné prostředí (jako command
) byly k dispozici také jako externí příkazy, bohužel to tak není command
na mnoha systémech. Například v operačních systémech Linux je zřídkakdy možné najít příkaz command
, zatímco většina z nich má which
příkaz (i když různé s různými možnostmi a chováním).
Případy, kdy můžete chtít externí příkaz, by byly všude, kde byste provedli příkaz bez vyvolání prostředí POSIX.
The system("some command line")
, popen()
… funkce jazyka C nebo různých jazyků vyvolávají prostředí pro analýzu tohoto příkazového řádku, takže system("command -v my-cmd")
pracují v nich. Výjimkou by byla perl
, která optimalizuje prostředí, pokud nevidí žádný speciální znak prostředí (jiný než mezeru). To platí také pro jeho operátor 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
Přidání výše uvedeného :;
výše nutí perl
vyvolat shell tam. Použitím which
byste tento trik nemuseli používat.
Komentáře
- @Joe,
which
jecsh
skript na mnoha komerčních Unices. Důvod je historický, proto ‚ proč jsem dal historii, aby lidé pochopili, odkud pochází, proč si je lidé zvykli používat a proč tam vlastně jsou ‚ není důvod, proč byste jej měli používat. A ano, někteří lidé používají (t) csh. Ještě ne všichni používají Linux - Po přečtení tohoto příspěvku jsem našel pro odpověď spoustu kontextů, ale ne samotnou odpověď.Kde v tomto příspěvku je vlastně řečeno, proč nepoužívat použít
which
, na rozdíl od věcí, které byste se mohli pokoušet použítwhich
úkoly, historiewhich
, implementacewhich
, další příkazy k provádění souvisejících úkolů nebo důvody pro skutečné použitíwhich
? Proč jsou ostatní příkazy lepší ? Co dělají jinak nežwhich
? Jak se vyhnou jeho nástrahám? Tato odpověď ve skutečnosti utratí více slov za problémy s alternativami, než za problémy popsané vwhich
. -
command
by POSIX. - @St é phaneChazelas Pokud vytvořím nový soubor pomocí
touch /usr/bin/mytestfile
a poté spustímcommand -v mytestfile
, dá cestu (zatímcowhich mytestfile
nikoli). - @jarno, ach ano, vy ‚ máte pravdu.
bash
se usadí na nespustitelném souboru, pokud ‚ nenalezne spustitelný soubor, takže ‚ s “ OK “ (i když v praxi by se radějicommand -v
/type
vrátit chybu), protože ‚ je příkaz, který by se pokusil provést při spuštěnímytestfile
, aledash
chování je buggy, jako by ‚ nebylo možné spustitcmd
před spustitelnýmcommand -v
vrací ten nespustitelný, zatímco spuštěnícmd
by spustil spustitelný (nesprávný jeden je také hašován). FreeBSDsh
(také na základěash
) má stejnou chybu. zsh, yash, ksh, mksh, bash as sh jsou v pořádku.
Odpověď
Důvody, proč člověk může Nechci používat which
již byly vysvětleny, ale zde je několik příkladů na několika systémech, kde which
skutečně selže.
Na skořápkách podobných Bourneovi porovnáváme výstup which
s výstupem type
(type
je vestavěný shell, znamená to základní pravdu, protože nám říká, jak vyvolá příkaz).
Mnoho případů je rohové případy, ale mějte na paměti, že which
/ type
se často používají v rohových případech (k nalezení odpovědi) k neočekávanému chování jako: proč se na Zemi tento příkaz chová takhle, kterému volám? ).
Většina systémů, většina shellů podobných Bourneovi: funkce
Nejviditelnější případ je pro funkce:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Důvodem je, že which
informuje pouze o spustitelných souborech a někdy o aliasech (i když ne vždy vašich ), nikoli o funkcích.
GNU, která má manuálovou stránku nefunkční (protože zapomněli citovat $@
) příklad, jak ji použít i pro hlášení funkcí, ale stejně jako pro aliasy, protože neimplementuje syntaktický analyzátor shellu, je snadno oklamán:
$ 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; }
Většina systémů, většina shellů typu Bourne: builtins
Dalším zjevným případem jsou vestavěné prvky nebo klíčová slova, protože which
být externím příkazem nemá žádný způsob, jak zjistit, která vestavěná prostředí má váš shell (a některé skořápky jako zsh
, bash
nebo ksh
lze načíst vestavěné soubory dynamicky):
$ 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
(to se nevztahuje na zsh
kde je which
zabudováno)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 a mnoho dalších:
$ 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
Je to proto, že na většině komerčních Unices which
(jako v původní implementaci) na 3BSD) je csh
skript, který čte ~/.cshrc
. Aliasy, které bude hlásit, jsou definované tam bez ohledu na aktuálně definované aliasy a bez ohledu na prostředí, které skutečně používáte.
V HP / UX nebo Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(verze Solaris a AIX tento problém vyřešily uložením $path
před přečtením ~/.cshrc
a obnovení před vyhledáním příkazů)
$ 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
Nebo:
$ 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
(Jako skript csh
samozřejmě nemůžete očekávat, že bude fungovat s argumenty obsahujícími mezery …)
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="
V tomto systému existuje celosystémově definovaný alias, který obsahuje příkaz GNU which
.
Falešný výstup je proto, že which
čte výstup bash
„s alias
ale neví, jak to správně analyzovat, a používá heuristiku (jeden alias na řádek, hledá první nalezený příkaz po |
, ;
, &
…)
Nejhorší na CentOS je to, že zsh
má naprosto skvělý which
vestavěný příkaz, ale CentOS se ho podařilo prolomit nahrazením nepracujícím aliasem GNU which
.
Debian 7.0, ksh93:
(platí pro většinu systémů s mnoha shelly)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
V Debianu, /bin/which
je /bin/sh
skript. V mém případě sh
je dash
, ale je to stejné, když je to bash
.
Zrušené nastavení PATH
neznamená deaktivaci PATH
vyhledávání, ale znamená použití systému výchozí PATH která bohužel na Debianu nikdo nesouhlasí (dash
a bash
mají /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
má /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
má /bin:/usr/bin
, mksh
má /usr/bin:/bin
($(getconf PATH)
), execvp()
(jako v env
) má :/bin:/usr/bin
(ano, nejprve se podívá do aktuálního adresáře!)) .
Což je důvod, proč which
se mýlí výše, protože používá dash
„výchozí PATH
který se liší od ksh93
„s
Je to ne lepší s GNU which
, které hlásí:
which: no which in ((null))
(zajímavé je, že skutečně existuje /usr/local/bin/which
v mém systému, což je vlastně akanga
skript, který byl dodán s akanga
(rc
shell derivát, kde výchozí PATH
je /usr/ucb:/usr/bin:/bin:.
))
bash, jakýkoli systém:
Ten, na který Chris odkazuje ve své odpovědi :
$ 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
Také po volání hash
ručně:
$ 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)
Nyní případ, kdy which
a někdy type
selhání:
$ 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
Nyní s několika skořápkami:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
S ostatními:
$ foo a/foo
Ani which
ani type
předem může vědět, že b/foo
nemůže b e provedeno. Některé skořápky jako bash
, ksh
nebo yash
při vyvolání foo
se skutečně pokusí spustit b/foo
a nahlásit chybu, zatímco ostatní (jako zsh
, ash
, csh
, Bourne
, tcsh
) poběží a/foo
při selhání execve()
systémového volání b/foo
.
Komentáře
-
mksh
pro výchozí$PATH
ve skutečnosti používá něco jiného , je použita časová konstanta operačního systému_PATH_DEFPATH
(nejčastěji na BSD), poté je použitaconfstr(_CS_PATH, …)
(POSIX), a pokud oba neexistují nebo selžou, použije se/bin:/usr/bin:/sbin:/usr/sbin
. - Ve vašem 1. příkladu, i když
ls
je funkce, kterou používá gls
z PATH. Awhich
vám řekne, který z nich je použit/usr/bin/ls
nebo/usr/local/bin/ls
. Nevidím ‚ nevidím “ Proč nepoužívat který “ …. - @rudimeier, To
which ls
mi dá/bin/ls
bez ohledu na to, zdals
/bin/ls
nebo/opt/gnu/bin/ls
nebodir
nebo vůbec nic. IOW,which
(ta, která implementace, IMMV) dává něco irelevantní - @St é phaneChazelas. Ne ne ne. Už vím , že můj
ls
je funkce. Vím že mojels
funkce voláls
zPATH
. Nyní miwhich
řekne, kde je soubor. Zobrazí se pouze jeden případ použití: “ Co by můj shell udělal s tímto příkazem. “ Pro tento případ použitíwhich
je špatně, správně.Existují však i jiné případy použití, kdy (GNU)which
je přesně to pravé. - @rudimeter, záleží na
which
implementace. Někteří vám řeknou, že ‚ je to alias (pokud máte nakonfigurovaný alias nebo je ve vaší domácnosti~/.cshrc
takový alias), některé vám za určitých podmínek poskytnou cestu, ale nesprávnou.sh -c 'command -v ls'
, i když není dokonalý, je pravděpodobnější, že vám dá správnou odpověď na tento odlišný požadavek (a je také standardní).
Odpověď
Jedna věc, která (z mého rychlého skimu) vypadá, že Stephane nezmínil, že which
má žádnou představu o hašovací tabulce cesty vašeho shellu. To má za následek, že může vrátit výsledek, který nereprezentuje to, co se vlastně spouští, což znemožňuje jeho ladění.
Odpovědět
Obvykle se krčím, když se tato otázka doporučuje nic netušícím uživatelům, protože nepodložené napadání which
není pro nikoho užitečné.
Pokud which
funguje dobře a poskytuje správnou odpověď na některý úkol podle motto Unixu: udělejte jednu věc, udělejte to dobře , proč by which
být zakázán?
Otázkou by tedy mělo být, který z nich funguje dobře a zvládne dobře konkrétní práci?
Jeden je externí nástroj na / bin / which v Debianu je shell skript, jehož cílem je pouze vypsat spustitelné soubory daného jména na cestě. Věřím, že which
plní svůj zamýšlený cíl správně. Načte žádné aliasy, žádné funkce, nic ze shellu, pouze vypíše první (nebo všechny) spustitelné soubory daného jména na PATH. což znamená nalezení souboru se stejným názvem, jaký je uveden, by měl uživatel (on) zjistit já.
Ano, jiné which
implementace mohou (a obvykle mají) konkrétní problémy.
Odpověď
Často slyšíme, čemu je třeba se vyhnout. Proč? Co bychom místo toho měli použít?
To jsem nikdy neslyšel. Uveďte konkrétní příklady. Dělal bych si starosti s vaší linuxovou distribucí a nainstalovanými softwarovými balíčky, protože odtud pochází which
!
SLES 11.4 x86-64
ve verzi tcsh 6.18.01:
> which which which: shell built-in command.
v bash verzi 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
je součástí util-linux standardní balíček distribuovaný organizací Linux Kernel Organization pro použití jako součást operačního systému Linux. Poskytuje také tyto další soubory
/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
můj util-linux
je verze 2.19. Poznámky k verzi lze snadno najít zpět na verzi v2.13 ze dne (28. 8. 2007). Nejste si jisti, jaký to má smysl nebo cíl, to rozhodně nebylo zodpovězeno v té zdlouhavé věci, hlasovalo 331krát.
Komentáře
- Všimněte si, otázka nezmiňuje to, na co Unix odkazuje. Linux je jen jedním z mála.
- Jak ukazuje váš
which -v
, GNU, který (extravagantní) je ‚ jeden zmíněný v druhé odpovědi a v žádném případě není specifický pro Linux), nikoli util-linux, který AFAIK nikdy neobsahoval nástrojwhich
. util-linux 2.19 je z roku 2011, GNU, který 2.19 je z roku 2008.
which
předpokládá interaktivní kontext prostředí. Tato otázka je označena tagem / přenositelností. Takže interpretuji otázka v této souvislosti jako “ co použít místowhich
k vyhledání prvního spustitelného jména daného jména v$PATH
„. Většina odpovědí a důvodů protiwhich
se zabývají aliasy, vestavěnými funkcemi a funkcemi, které jsou ve většině přenosných shell skriptů v reálném světě jen akademickým zájmem. Lokálně definované aliasy nejsou ‚ zděděny při spuštění skriptu prostředí (pokud jej nezískáte pomocí.
).csh
(awhich
je stálecsh
skript na většině komerčních Unices) přečte~/.cshrc
, pokud není interaktivní. ‚ Proto si ‚ všimnete, že skripty csh obvykle začínají#! /bin/csh -f
.which
ne proto, že má za cíl poskytnout vám aliasy, protože to ‚ znamená jako nástroj pro (interaktivní) uživatelécsh
. Uživatelé POSIX skořápek majícommand -v
.(t)csh
(nebo vám ‚ nevadí, pokud vám nedává ‚ správný výsledek), použijtetype
nebocommand -v
místo . Přečtěte si odpovědi proč .stat $(which ls)
se mýlí z několika důvodů (chybí--
, chybějící uvozovky), nejen použitíwhich
). ‚ použijetestat -- "$(command -v ls)"
. To předpokládá, žels
je skutečně příkaz nalezený v systému souborů (nejde o vestavěný shell nebo funkci aliasu).which
vám může dát špatnou cestu (nikoli cestu, kterou by provedl váš shell, pokud jste zadalils
) nebo vám dá alias, jak je definován v konfiguraci některých dalších skořápek …which
neposkytlo anils
který by byl nalezen vyhledáním$PATH
(bez ohledu na to, cols
může vyvolat ve vašem shellu).sh -c 'command -v ls'
nebozsh -c 'rpm -q --whatprovides =ls'
vám pravděpodobně dají správnou odpověď. Jde o to, žewhich
je rozbité dědictví zcsh
.