Ve většině shellů nullglob není výchozí. To znamená, že například spustíte tento příkaz
ls *
v prázdném adresáři rozbalí * glob na doslovný * místo na prázdný seznam argumentů. Existují způsoby, jak toto chování změnit, takže * v prázdném adresáři vrátí prázdný seznam argumentů, což by se zdálo intuitivnější.
Existuje tedy důvod, proč nullglob je ve výchozím nastavení zakázáno? Pokud ano, jaký je ten důvod?
Přijatá odpověď:
nullglob možnost (která je mimochodem zsh vynález, jen o roky později přidán do bash (2.0 )) by v řadě případů nebylo ideální. A ls je dobrý příklad:
ls *.txt
Nebo jeho správnější ekvivalent:
ls -- *.txt
Pomocí nullglob on by spustil ls bez argumentu, který je považován za ls -- . (vypište aktuální adresář), pokud se žádné soubory neshodují, což je pravděpodobně horší než volání ls s doslovným *.txt jako argument.
Podobné problémy byste měli s většinou textových nástrojů:
grep foo *.txt
Hledal by foo na stdin, pokud neexistuje txt soubor.
Rozumnějším výchozím nastavením, jako je csh, tcsh, zsh nebo fish 2.3+ (a dřívějších unixových shellů), je úplně zrušit příkaz, pokud glob neodpovídá.
bash (od verze 3) má failglob možnost pro to (zajímavé pro tuto diskusi, protože na rozdíl od ash , AT&T ksh nebo zsh , bash nepodporuje místní rozsahy možností (ačkoli to se ve verzi 4.4 změní), tato možnost, když je povolena globálně, narušuje několik věcí, jako jsou funkce dokončování bash.
Všimněte si, že csh a tcsh se mírně liší od zsh , fish nebo bash -O failglob v případech jako:
ls -- *.txt *.html
Kde potřebujete, aby se všechny koule neshodovaly, aby byl příkaz zrušen. Pokud například existuje jeden soubor txt a žádný soubor html, bude to:
ls -- file.txt
Toto chování můžete získat pomocí zsh pomocí setopt cshnullglob i když rozumnější způsob, jak to udělat v zsh by bylo použít glob jako:
ls -- *.(txt|html)
V zsh a ksh93 , můžete také použít nullglob na základě jednotlivých zemí, což je mnohem rozumnější přístup než úprava globálního nastavení:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
by vytvořilo prázdné pole, pokud neexistuje žádný txt namísto selhání příkazu s chybou (nebo vytvoření pole s jedním *.txt doslovný argument s jinými shelly).
Verze fish před 2.3 by fungovalo jako bash -O nullglob ale dávat varování, když je interaktivní, když globus nemá žádnou shodu. Od verze 2.3 funguje jako zsh kromě globů používaných v for , set nebo count .
Nyní, pokud jde o historii, chování bylo ve skutečnosti přerušeno od Bourne shellu. V předchozích verzích Unixu se globování provádělo prostřednictvím /etc/glob helper a ten se choval jako csh :příkaz by selhal, pokud by žádný z globů neodpovídal žádnému souboru, a jinak by globy bez shody odstranil.
Takže situace, ve které jsme dnes, je způsobena špatným rozhodnutím učiněným v Bourneově shellu.
Všimněte si, že Bourne shell (a shell C) přišel s další novou funkcí Unixu:prostředím. To znamenalo variabilní rozšíření (jeho předchůdce měl pouze $1 , $2 … polohové parametry). Bourne shell také zavedl substituci příkazů.
Dalším špatným návrhovým rozhodnutím Bourne shellu bylo provést globování (a rozdělení) po expanzi proměnných a substituci příkazů (možná kvůli zpětné kompatibilitě s Thompsonovým shellem, kde echo $1 by stále vyvolávalo /etc/glob pokud $1 obsahoval zástupné znaky (tady to bylo spíše jako expanze makra preprocesoru, protože v rozšířené hodnotě byla znovu analyzována jako shell kód)).
Selhání koulí, které se neshodují, by například znamenalo:
pattern='a.*b'
grep $pattern file
by selhal příkaz (pokud tam nejsou nějaké a.whateverb soubory v aktuálním adresáři). csh (který také provádí globování při rozšiřování proměnné) v takovém případě příkaz selže (a řekl bych, že je to lepší, než tam nechat spící chybu, i když to není tak dobré, jako když globování neprovádíte vůbec jako v zsh ).