¿Por qué la ordenación ls ignora los caracteres no alfanuméricos?

25

Al ordenar los nombres de archivo, lsignora los caracteres como -,_. Esperaba que también usara esos caracteres en la clasificación.

Un ejemplo:

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

Ahora muestre estos archivos con ls -1:

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

Lo que esperaba era algo como esto:

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

es decir, esperaba que los caracteres no alfanuméricos se tengan en cuenta al ordenar.

¿Alguien puede explicar este comportamiento? ¿Es este comportamiento obligatorio por un estándar? ¿O esto se debe a que la codificación es UTF-8?

Actualización: Parece que esto está relacionado con la clasificación 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
fuente
2
UTF-8 y ASCII son idénticos si todo lo que está usando son los primeros 128 puntos de código (que es su ejemplo). ¿Qué pasa si lo haces LC_COLLATE=C ls?
Alexios
El problema no es que ASCII y UTF-8 sean idénticos, sino que UTF-8 tiene sus propias reglas de clasificación (clasificación).
daniel kullmann
1
Sí, es cierto que [_-,.]están siendo agrupados y de alguna manera semi-ignorados. No sé exactamente cómo o dónde se define dicha clasificación, pero debe ser un problema de clasificación, porque simplemente, y solo, cambiar la clasificación a C (vía LC_COLLATE=C ls -l) es suficiente para darle el orden de clasificación que esperaba (suponiendo que LC_ALLes no anulando LC_COLLATE). Esto es válido para toda la gama de caracteres en el plano multilingüe básico Unicode ... He editado mi respuesta para incluir un script de ejemplo que lo
confirme
si no le gusta cómo funciona, puede crear un alias y ponerlo en su ~ / .profile: alias ls = 'LC_COLLATE = C ls' </kbd>
jippie

Respuestas:

10

Esto no tiene nada que ver con el juego de caracteres. Más bien, es el lenguaje el que determina el orden de clasificación. La biblioteca examina el lenguaje presentado en $LC_COLLATE/ $LC_ALL/ $LANGy busca sus reglas de clasificación (por ejemplo, /usr/share/i18n/locales/*para GLibC) y ordena el texto según las instrucciones.

Ignacio Vazquez-Abrams
fuente
FYI: Es más complicado que esto. Si se usara uno, strcollpor ejemplo, vería que algo así se aasa.cordenaría arriba aas.c.
Don Scott
12

EDITAR: Prueba agregada para datos ordenados con LC_COLLATE = C


La secuencia de clasificación predeterminada es tratar esos caracteres de "tipo de puntuación" como de igual valor ... Use LC_COLLATE=Cpara tratarlos en orden de punto 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

Salida

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

El siguiente código prueba todos los caracteres UTF-8 válidos en el plano multilingüe básico (excepto \ x00 y \ x0a ; por simplicidad)
Compara un archivo en una secuencia ascendente conocida (generada), contra ese archivo ordenado aleatoriamente y luego ordenado nuevamente con LC_COLLATE = C. El resultado muestra que la secuencia C es idéntica a la secuencia original generada.

{ 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 $?='$?

Salida:

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

cmp $?=0
Peter.O
fuente
2
¿Dónde está documentado eso? ¿Es eso parte del estándar Unicode?
daniel kullmann
2
En realidad, no obtienen el mismo valor; esos caracteres simplemente se ignoran al ordenar. Si se tratara como si tuvieran el mismo valor, el orden de clasificación a_1 a2 a_2sería imposible.
daniel kullmann
+1 por su trabajo duro y código de muestra. Después de muchas horas, ordenar los nombres de los directorios con signos de puntuación para que coincidan con la forma tree, creo que hay más en la historia, como la eliminación de la puntuación de las cadenas de comparación o algo así. Puedo decir que el /carácter tiene que establecerse como el carácter más bajo en la secuencia de clasificación sin importar qué más.
WinEunuuchs2Unix