Por que a classificação ls ignora caracteres não alfanuméricos?

25

Ao classificar nomes de arquivos, lsignora caracteres como -,_. Eu esperava que ele usasse esses caracteres na classificação também.

Um exemplo:

touch a1 a2 a-1 a-2 a_1 a_2 a.1 a.2 a,1 a,2

Agora exiba esses arquivos com ls -1:

a1
a_1
a-1
a,1
a.1
a2
a_2
a-2
a,2
a.2

O que eu esperava era algo assim:

a1
a2
a,1
a,2
a.1
a.2
a_1
a_2
a-1
a-2

ou seja, eu esperava que os caracteres não alfanuméricos fossem levados em consideração ao classificar.

Alguém pode explicar esse comportamento? Esse comportamento é determinado por um padrão? Ou isso ocorre porque a codificação é UTF-8?

Atualização: Parece que isso está relacionado à classificação UTF-8:

$ LC_COLLATE=C ls -1
a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2
daniel kullmann
fonte
2
UTF-8 e ASCII são idênticos se você estiver usando apenas os primeiros 128 pontos de código (como é o seu exemplo). O que acontece se você fizer LC_COLLATE=C ls?
Alexios1
O problema não é que ASCII e UTF-8 sejam idênticos, mas sim que o UTF-8 tenha suas próprias regras de ordenação (classificação).
Daniel kullmann 01/04/12
11
Sim, é verdade que [_-,.]estão sendo agrupados e de alguma forma semi-ignorados. Não sei exatamente como ou onde esse agrupamento é definido, mas deve ser um problema de agrupamento, porque simplesmente, e apenas, alterar o agrupamento para C (via LC_COLLATE=C ls -l) é suficiente para fornecer a ordem de classificação que você esperava (assumindo que LC_ALLé não substituindo LC_COLLATE). Isso vale para toda a gama de caracteres no Unicode Basic Multilingual Plane ... Eu editei a minha resposta para incluir um script de exemplo que confirma isso ...
Peter.O
Se você não gosta como ele funciona, você pode criar um alias e colocá-lo em seu ~ / .profile: ls alias = 'LC_COLLATE = C ls' </ kbd>
jippie

Respostas:

10

Isso não tem nada a ver com o conjunto de caracteres. Pelo contrário, é a linguagem que determina a ordem de intercalação. O libc examina o idioma apresentado em $LC_COLLATE/ $LC_ALL/ $LANGe /usr/share/i18n/locales/*consulta suas regras de agrupamento (por exemplo, para GLibC) e ordena o texto conforme indicado.

Ignacio Vazquez-Abrams
fonte
FYI: É mais complicado que isso. Se alguém usasse, strcollpor exemplo, você veria que algo como aasa.cseria classificado acima aas.c.
Don Scott
12

EDIT: teste adicionado para dados classificados com LC_COLLATE = C


A sequência de intercalação padrão é tratar esses caracteres "do tipo pontuação" como sendo de igual valor .. Use LC_COLLATE=Cpara tratá-los na ordem do ponto de código.

for i in 'a1' 'a_1' 'a-1' 'a,1' 'a.1' 'a2' 'a_2' 'a-2' 'a,2' 'a.2' ;do
  echo $i; 
done |LC_COLLATE=C sort

Saída

a,1
a,2
a-1
a-2
a.1
a.2
a1
a2
a_1
a_2

O código que se segue testa todos válidos UTF-8 caracteres no básica multilingues plana (excepto para \ x00 e \ x0a ; para simplicidade)
Compara um ficheiro num (gerado) sequência ascendente conhecida, contra esse ficheiro ordenados aleatoriamente e então classificados novamente com LC_COLLATE = C. O resultado mostra que a sequência C é idêntica à sequência gerada original.

{ i=0 j=0 k=0 l=0
  for i in {0..9} {A..F} ;do
  for j in {0..9} {A..F} ;do
  for k in {0..9} {A..F} ;do
  for l in {0..9} {A..F} ;do
     (( 16#$i$j$k$l == 16#0000 )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l == 16#000A )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#D800    && 
        16#$i$j$k$l <= 16#DFFF )) && { printf '.' >&2; continue; }
     (( 16#$i$j$k$l >= 16#FFFE )) && { printf '.' >&2; continue; }
     echo 0x"$i$j$k$l" |recode UTF-16BE/x4..UTF-8 || { echo "ERROR at codepoint $i$j$k$l " >&2; continue; } 
     echo 
  done
  done
  done; echo -n "$i$j$k$l " >&2
  done; echo >&2
} >listGen

             sort -R listGen    > listRandom
LC_COLLATE=C sort    listRandom > listCsort 

diff <(cat listGen;   echo "last line of listOrig " ) \
     <(cat listCsort; echo "last line of listCsort" )
echo 
cmp listGen listCsort; echo 'cmp $?='$?

Saída:

63485c63485
< last line of listOrig 
---
> last line of listCsort

cmp $?=0
Peter.O
fonte
2
Onde isso está documentado? Isso faz parte do padrão Unicode?
Daniel kullmann
2
Na verdade, eles não recebem o mesmo valor; esses caracteres são simplesmente ignorados ao classificar. Se eles fossem tratados como tendo um valor igual, a ordem de classificação a_1 a2 a_2seria impossível.
Daniel kullmann
+1 pelo seu trabalho árduo e código de exemplo. Depois de muitas horas classificando os nomes dos diretórios com pontuação para combinar com o treeque eu acho, acho que há mais na história, como a pontuação sendo removida das seqüências de comparação ou algo assim. Posso dizer que o /caractere deve ser definido como o caractere mais baixo na sequência de intercalação, não importa o que mais.
WinEunuuchs2Unix