GNU/Linux >> Znalost Linux >  >> Linux

Vytváří Bash Star * Zástupný znak vždy (vzestupně) seřazený seznam?

Mám adresář plný souborů s názvy jako logXX kde XX je dvouznakové hexadecimální číslo odložené nulou, například:

log00
log01
log02
...
log0A
log0B
log0C
...
log4E
log4F
log50
...

Obecně bude celkem méně než řekněme 20 nebo 30 souborů. Datum a čas v mém konkrétním systému není něco, na co se lze spolehnout (vestavěný systém bez spolehlivých zdrojů času NTP nebo GPS). Názvy souborů se však budou spolehlivě zvyšovat, jak je uvedeno výše.

Chci grep doufal jsem, že projdu všechny soubory pro poslední záznam protokolu určitého typu cat soubory dohromady, například…

cat /tmp/logs/log* | grep 'WARNING 07 -' | tail -n1

Napadlo mě však, že různé verze bash nebo sh nebo zsh atd. mohou mít různé představy o tom, jak * je rozšířena.

man bash stránka neříká, zda rozšíření * či nikoli by byl rozhodně vzestupný abecední seznam odpovídajících názvů souborů. Zdá se, že stoupá pokaždé, když to zkouším na všech systémech, které mám k dispozici – ale jedná se o DEFINOVANÉ chování nebo pouze o specifickou implementaci?

Jinými slovy, mohu se absolutně spolehnout na cat /tmp/logs/log* zřetězit všechny mé soubory protokolu dohromady v abecedním pořadí?

Přijatá odpověď:

Ve všech shellech jsou globusy standardně seřazeny. Byly již součástí /etc/glob pomocník povolaný shellem Kena Thompsona k rozšíření globů v první verzi Unixu na počátku 70. let (a která dala globům jejich jméno).

Pro sh , POSIX vyžaduje, aby byly seřazeny pomocí strcoll() , což je použití pořadí řazení v národním prostředí uživatele, jako pro ls i když někteří to stále dělají pomocí strcmp() , který je založen pouze na hodnotách bajtů.

$ dash -c 'echo *'
Log01B log-0D log00 log01 log02 log0A log0B log0C log4E log4F log50 log① log② lóg01
$ bash -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ zsh -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ ls
log②  log①  log00  log01  lóg01  Log01B  log02  log0A  log0B  log0C  log-0D  log4E  log4F  log50
$ ls | sort
log②
log①
log00
log01
lóg01
Log01B
log02
log0A
log0B
log0C
log-0D
log4E
log4F
log50

Výše si můžete všimnout, že u těch shellů, které třídí na základě národního prostředí, zde na systému GNU s en_GB.UTF-8 národní prostředí, - v názvech souborů je ignorováno pro řazení (většina interpunkčních znaků by). ó se třídí očekávanějším způsobem (alespoň pro Brity) a velká a malá písmena se ignorují (kromě případů, kdy dojde na rozhodování o remíze).

U log① log② si však všimnete určitých nesrovnalostí. Je to proto, že pořadí řazení ① a ② není definováno v národních prostředích GNU (aktuálně; doufejme, že to jednoho dne bude opraveno). Třídí stejně, takže získáte náhodné výsledky.

Související:Zpracovat potomky?

Změna národního prostředí ovlivní pořadí řazení. Můžete nastavit národní prostředí na C a získat strcmp() -jako řazení:

$ bash -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0.2 log0A log0B log0C log-0D log4E log4F log50
$ bash -c 'LC_ALL=C; echo *'
Log01B log-0D log0.2 log00 log01 log02 log0A log0B log0C log4E log4F log50 log① log② lóg01

Všimněte si, že některá národní prostředí mohou způsobit určité zmatky i pro řetězce all-ASCII all-alnum. Jako ty české (alespoň na systémech GNU), kde ch je prvek řazení který se řadí po h :

$ LC_ALL=cs_CZ.UTF-8 bash -c 'echo *'
log0Ah log0Bh log0Dh log0Ch

Nebo, jak poukázal @ninjalj, ještě podivnější v maďarských lokalitách:

$ LC_ALL=hu_HU.UTF-8 bash -c 'echo *'
logX LOGx LOGX logZ LOGz LOGZ logY LOGY LOGy

V zsh , můžete zvolit řazení pomocí glob kvalifikátorů. Například:

echo *(om) # to sort by modification time
echo *(oL) # to sort by size
echo *(On) # for a *reverse* sort by name
echo *(o+myfunction) # sort using a user-defined function
echo *(N)  # to NOT sort
echo *(n)  # sort by name, but numerically, and so on.

Číselný druh echo *(n) lze také povolit globálně pomocí numericglobsort možnost:

$ zsh -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0.2 log0A log0B log0C log-0D log4E log4F log50
$ zsh -o numericglobsort -c 'echo *'
log① log② log00 lóg01 Log01B log0.2 log0A log0B log0C log01 log02 log-0D log4E log4F log50

Pokud jste (stejně jako já) zmateni tímto pořadím v tomto konkrétním případě (zde pomocí mého britského národního prostředí), podrobnosti naleznete zde.


Linux
  1. Účel .bashrc a jak to funguje?

  2. The Bash ‘?

  3. Jak přizpůsobit automatické doplňování Bash tak, aby vypisovalo soubory v jiném adresáři?

  1. Proč Regex v Bash funguje pouze v případě, že je proměnnou a ne přímo?

  2. Jak vypsat velikost každého souboru a adresáře a seřadit podle sestupné velikosti v Bash?

  3. Co dělá 'bash -c'?

  1. Příkaz „eval“ v Bash?

  2. Má ~ Vždy stejný $domov?

  3. Escape znak hvězdičky (*) v bash