Vím, že používám příkaz ls
zobrazí seznam všech adresářů. Ale co dělá ls *
příkaz udělat? Použil jsem to a uvádí pouze adresáře. Má hvězdička před ls
znamená, jak hluboko bude seznam adresářů?
Přijatá odpověď:
ls
vypíše soubory a obsah adresářů, které jsou předávány jako argumenty, a pokud není zadán žádný argument, vypíše aktuální adresář. Lze mu také předat řadu voleb, které ovlivňují jeho chování (viz man ls
pro podrobnosti).
Pokud ls
je předán argument nazvaný *
, vyhledá soubor nebo adresář s názvem *
v aktuálním adresáři a vypsat jej jako kterýkoli jiný. ls
nezachází s *
znak jakýmkoli jiným způsobem než jakýmkoli jiným.
Pokud však ls *
je shell příkazového řádku, to je kód v jazyce unixového shellu , pak shell rozbalí tento *
podle jeho globování (také označované jako Generování názvu souboru nebo Rozšíření názvu souboru/cesty ) pravidla.
Zatímco různé shelly podporují různé globbingové operátory, většina z nich se shoduje na tom nejjednodušším *
. *
jako vzor znamená libovolný počet znaků, takže *
jako glob
se rozbalí na seznam souborů v aktuálních adresářích, které odpovídají tomuto vzoru. Existuje však výjimka, že úvodní tečka (.
) znak v názvu souboru musí být explicitně shodný, takže *
ve skutečnosti expanduje na seznam souborů a adresářů, které nezačínají .
(v lexikálním pořadí).
Například, pokud aktuální adresář obsahuje soubory s názvem .
, ..
, .foo
, -l
a foo bar
, *
bude shellem rozšířen na dva argumenty, které se předají ls
:-l
a foo bar
, takže to bude, jako byste napsali:
ls -l "foo bar"
nebo
'ls' "-l" foo bar
Což jsou tři způsoby, jak spustit úplně stejný příkaz. Ve všech 3 případech ls
příkaz (který bude pravděpodobně spuštěn z /bin/ls
z vyhledávání adresářů uvedených v $PATH
) budou předány tyto 3 argumenty:„ls“, „-l“ a „foo bar“.
Mimochodem, v tomto případě ls
bude zacházet s prvním (přesně řečeno druhým ) jeden jako možnost.
Nyní, jak jsem řekl, různé shelly mají různé globbingové operátory. Před několika desetiletími zsh
představil **/
operator¹, což znamená, že odpovídá jakékoli úrovni podadresářů, zkratka pro (*/)#
a ***/
což je stejné až na to, že při sestupu v adresářích následuje symbolické odkazy.
Před několika lety (červenec 2003, ksh93o+
), ksh93
se rozhodl zkopírovat toto chování, ale rozhodl se, že bude nepovinné a pokryje pouze **
případ (nikoli ***
). Také, zatímco **
samotný nebyl v zsh
speciální ² (myšleno totéž jako *
jako v jiných tradičních shellech od **
znamená libovolný počet znaků následovaný libovolným počtem znaků), v ksh93 **
znamená totéž jako **/*
(tedy jakýkoli soubor nebo adresář pod aktuálním (kromě skrytých souborů)³.
bash
zkopírován ksh93
o několik let později (únor 2009, bash 4.0), se stejnou syntaxí, ale nešťastným rozdílem:bash's **
bylo jako zsh
„s ***
, to znamená, že to bylo sledování symbolických odkazů při návratu do podadresářů, což obecně není to, co chcete, aby to dělalo, a může to mít nepříjemné vedlejší účinky. V bash-4.3 to bylo částečně opraveno v tom, že se stále dodržovaly symbolické odkazy, ale tam se rekurze zastavila. Ve verzi 5.0 to bylo plně opraveno.
yash
přidán **
ve verzi 2.0 v roce 2008, povoleno pomocí extended-glob
volba. Jeho implementace je blíže k zsh
's v tom **
sám není zvláštní. Ve verzi 2.15 (2009) přidal ***
jako v zsh
a dvě vlastní přípony:.**
a .***
pro zahrnutí skrytých adresářů při opakování (v zsh
, D
kvalifikátor glob (jako v **/*(D)
) bude zvažovat skryté soubory a adresáře, ale pokud chcete pouze procházet skryté adresáře, ale ne rozbalovat skryté soubory, potřebujete ((*|.*)/)#*
nebo **/[^.]*(D)
).
Rybí skořápka také podporuje **
. Stejně jako předchozí verze bash
, následuje symbolické odkazy při sestupu do adresářového stromu. V tomto shellu však **/*
není totéž jako **
. **
je spíše rozšířením *
které mohou zahrnovat několik adresářů. V fish
, **/*.c
bude odpovídat a/b/c.c
ale ne a.c
, zatímco a**.c
bude odpovídat a.c
a ab/c/d.c
a zsh
‘s **/.*
například musí být napsáno .* **/.*
. Tady, ***
je chápán jako **
následovaný *
tedy stejně jako **
.
tcsh
také přidán globstar
možnost ve V6.17.01 (květen 2010) a podporuje obě **
a ***
à la zsh
.
Tedy v tcsh
, bash
a ksh93
, (když je povolena odpovídající možnost (globstar
)) nebo fish
, **
rozbalí všechny soubory a adresáře pod aktuálním souborem a ***
je stejný jako **
pro fish
, symbolický odkaz procházející **
pro tcsh
s globstar
a stejné jako *
v bash
a ksh93
(ačkoli není vyloučeno, že budoucí verze těchto shellů budou také procházet symbolické odkazy).
Výše jste si všimli, že je potřeba zajistit, aby žádné z rozšíření nebylo interpretováno jako možnost. Pro to byste udělali:
ls -- *
Nebo:
ls ./*
Existují nějaké příkazy (nezáleží na tom pro ls
), kde je vhodnější druhý, protože i s --
některé názvy souborů mohou být ošetřeny speciálně. To je případ -
pro většinu textových nástrojů cd
a pushd
a názvy souborů, které obsahují =
znak pro awk
například. Před ./
všem argumentům odstraňuje jejich zvláštní význam (alespoň pro případy uvedené výše).
Je třeba také poznamenat, že většina shellů má řadu možností, které ovlivňují chování globbingu (např. zda jsou soubory s tečkami ignorovány nebo ne, pořadí řazení, co dělat, pokud neexistuje žádná shoda…), viz také $FIGNORE
parametr v ksh
Také v každém shellu kromě csh
, tcsh
, fish
a zsh
, pokud vzor koule neodpovídá žádnému souboru, vzor je předán jako nerozbalený argument, což způsobuje zmatek a možná i chyby. Pokud například v aktuálním adresáři není žádný neskrytý soubor
ls *
Ve skutečnosti zavolá ls
se dvěma argumenty ls
a *
. A protože neexistuje vůbec žádný soubor, tak žádný s názvem *
buď se zobrazí chybová zpráva od ls (ne shell) jako:ls: cannot access *: No such file or directory
, o kterém je známo, že si lidé myslí, že to byl ls
to ve skutečnosti rozšiřovalo koule.
Problém je ještě horší v případech jako:
rm -- *.[ab]
Pokud neexistuje *.a
ani *.b
soubor v aktuálním adresáři, pak můžete skončit smazáním souboru s názvem *.[ab]
omylem (csh
, tcsh
a zsh
by nahlásil žádnou shodu chyba a nezavolá rm
(a fish
nepodporuje [...]
zástupné znaky)).
Pokud chcete předat doslovný *
na ls
, musíte uvést, že *
znak nějakým způsobem jako v ls *
nebo ls '*'
nebo ls "*"
. V shellech podobných POSIXu lze globování úplně zakázat pomocí set -o noglob
nebo set -f
(poslední nefunguje v zsh
pokud není v sh
/ksh
emulace).
.