Proč nepoužívat “ which ”? Co tedy použít?

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

  • Myslím, že většina argumentů proti použití 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ísto which k vyhledání prvního spustitelného jména daného jména v $PATH „. Většina odpovědí a důvodů proti which 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í .).
  • @MattBianco, ano, csh (a which je stále csh 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.
  • @rudimeier, pak by odpověď byla vždy, pokud váš shell není (t)csh (nebo vám ‚ nevadí, pokud vám nedává ‚ správný výsledek), použijte type nebo command -v místo . Přečtěte si odpovědi proč .
  • @rudimeier, (stat $(which ls) se mýlí z několika důvodů (chybí --, chybějící uvozovky), nejen použití which). ‚ použijete stat -- "$(command -v ls)". To předpokládá, že ls 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 zadali ls) nebo vám dá alias, jak je definován v konfiguraci některých dalších skořápek …
  • @rudimeier opět existuje řada podmínek, za kterých by vám mnoho implementací which neposkytlo ani ls který by byl nalezen vyhledáním $PATH (bez ohledu na to, co ls může vyvolat ve vašem shellu). sh -c 'command -v ls' nebo zsh -c 'rpm -q --whatprovides =ls' vám pravděpodobně dají správnou odpověď. Jde o to, že which je rozbité dědictví z csh.

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 jakowhichv 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 se execve systémové volání nevrátí s chybou. Pokud například $PATH obsahuje /foo:/bar a chcete spustit ls, 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 jako ash, pdksh nebo zsh může také vrátit foo 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říklad mount je pro busybox někdy zabudován sh) a například bash 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 …), ale command -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 nebo echo=$commands[echo] nebo echo=${${:-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 je csh 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žít which úkoly, historie which, implementace which, 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é v which.
  • command by POSIX.
  • @St é phaneChazelas Pokud vytvořím nový soubor pomocí touch /usr/bin/mytestfile a poté spustím command -v mytestfile, dá cestu (zatímco which 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ěji command -v / type vrátit chybu), protože ‚ je příkaz, který by se pokusil provést při spuštění mytestfile, ale dash chování je buggy, jako by ‚ nebylo možné spustit cmd před spustitelným command -v vrací ten nespustitelný, zatímco spuštění cmd by spustil spustitelný (nesprávný jeden je také hašován). FreeBSD sh (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/bin:/usr/bin:/usr/ucb:/usr/local/bin, ksh93/bin:/usr/bin, mksh/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žita confstr(_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á g ls z PATH. A which 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, zda ls /bin/ls nebo /opt/gnu/bin/ls nebo dir 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 moje ls funkce volá ls z PATH. Nyní mi which ř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ástroj which. util-linux 2.19 je z roku 2011, GNU, který 2.19 je z roku 2008.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *