Ao classificar nomes de arquivos, ls
ignora 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 durante a classificação.
Alguém pode explicar esse comportamento? Esse comportamento é exigido por um padrão? Ou isso se deve à codificação ser UTF-8?
Atualizar: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
Responder1
EDIT: Adicionado teste para dados classificados com LC_COLLATE=C
A sequência de agrupamento padrão trata esses caracteres do "tipo de pontuação" como sendo de valor igual.. Use LC_COLLATE=C
para 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 a seguir testa todosválidoCaracteres UTF-8 no Plano Multilíngue Básico (exceto para\x00e\x0a; para simplificar)
Ele compara um arquivo em uma sequência ascendente conhecida (gerada), com aquele arquivo classificado aleatoriamente e depois classificado novamente com LC_COLLATE=C. O resultado mostra queCsequência é idêntica à sequência original gerada.
{ 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
Responder2
Isso não tem nada a ver com o conjunto de caracteres. Em vez disso, é o idioma que determina a ordem de agrupamento. A libc examina a linguagem apresentada em $LC_COLLATE
/ $LC_ALL
/ $LANG
e procura suas regras de agrupamento (por exemplo, /usr/share/i18n/locales/*
para GLibC) e ordena o texto conforme indicado.
Responder3
Estou tendo exatamente o mesmo problema com as opções de classificação padrão do Debian, para mim é uma vírgula que ele está ignorando e que está me impedindo de classificar dados CSV de maneira eficaz, causando estragos em minha IA.
A solução é, em vez de usar sort
por conta própria, preciso forçar a classificação do comportamento padrão que parece ser -d, --dictionary-order
.
Executando o comando:
sort -V
Resolve meu problema e considera vírgulas.
Responder4
só um comentário... tenho um grande problema com meu agrupamento (es_AR.utf8) porque não posso usar 'C' porque os acentos e o pior de tudo é que o problema aparece no banco de dados postgresql também fazendo com que a frase entre '10 ' e '10.1' incluem (é um exemplo) o valor '100' que não espero .. acho que tenho que usar o agrupamento em cada consulta .. SELECIONE '100' ENTRE '10' E '10.Z 'mostra verdadeiro, mas SELECT '100' BETWEEN '10' AND '10.Z' COLLATE "C" mostra 'falso', o que é correto (na minha opinião)