Pourquoi le tri ls ignore-t-il les caractères non alphanumériques?


25

Lors du tri des noms de fichiers, lsignore les caractères comme -,_. Je m'attendais à ce qu'il utilise également ces caractères dans le tri.

Un exemple:

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

Affichez maintenant ces fichiers avec ls -1:

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

Je m'attendais à quelque chose comme ça:

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

c'est-à-dire que je m'attendais à ce que les caractères non alphanumériques soient pris en compte lors du tri.

Quelqu'un peut-il expliquer ce comportement? Ce comportement est-il imposé par une norme? Ou est-ce dû au fait que l'encodage est UTF-8?

Mise à jour: Il semble que cela soit lié au tri 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

2
UTF-8 et ASCII sont identiques si vous n'utilisez que les 128 premiers points de code (dont votre exemple est). Que se passe-t-il si vous le faites LC_COLLATE=C ls?
— Alexios

Le problème n'est pas que ASCII et UTF-8 sont identiques, c'est plutôt que UTF-8 a ses propres règles de classement (tri).
— daniel kullmann

1
Oui, c'est vrai qui [_-,.]sont regroupés et en quelque sorte semi-ignorés. Je ne sais pas exactement comment ou où une telle collecte est définie, mais il doit être un problème de classement, parce que tout simplement, et seulement, en changeant la collation C (via LC_COLLATE=C ls -l) est suffisant pour vous donner l'ordre de tri que vous attendiez ( en supposant que LC_ALLest pas prioritaire LC_COLLATE). Cela est vrai pour toute la gamme de caractères dans le plan multilingue de base Unicode ... J'ai modifié ma réponse pour inclure un exemple de script qui
— confirme

si vous n'aimez pas comment cela fonctionne, vous pouvez créer un alias et le mettre dans votre ~ / .profile: alias ls = 'LC_COLLATE = C ls' </kbd>
— jippie

Réponses:


10

Cela n'a rien à voir avec le jeu de caractères. C'est plutôt le langage qui détermine l'ordre de classement. La libc examine le langage présenté dans $LC_COLLATE/ $LC_ALL/ $LANGet recherche ses règles de classement (par exemple /usr/share/i18n/locales/*pour GLibC) et ordonne le texte comme indiqué.


FYI: C'est plus compliqué que cela. Si l'on devait utiliser strcollpar exemple, vous verriez que quelque chose comme aasa.cserait trié ci-dessus aas.c.
— Don Scott

12

EDIT: Test ajouté pour les données triées avec LC_COLLATE = C


La séquence d'assemblage par défaut traite ces caractères de "type ponctuation" comme étant de valeur égale .. Use LC_COLLATE=Cpour les traiter dans l'ordre des points de code ..

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

Sortie

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

Le code suivant teste tous les caractères UTF-8 valides dans le plan multilingue de base (sauf pour \ x00 et \ x0a ; pour plus de simplicité)
Il compare un fichier dans une séquence ascendante connue (générée), avec ce fichier trié aléatoirement puis trié à nouveau avec LC_COLLATE = C. Le résultat montre que la séquence C est identique à la séquence générée d'origine.

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

Sortie:

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

cmp $?=0

2
Où est-ce documenté? Cela fait-il partie de la norme Unicode?
— daniel kullmann

2
En fait, ils n'obtiennent pas la même valeur; ces caractères sont simplement ignorés lors du tri. S'ils étaient traités comme ayant une valeur égale, l'ordre de tri a_1 a2 a_2serait impossible.
— daniel kullmann

+1 pour votre travail acharné et exemple de code. Après de nombreuses heures à trier les noms de répertoire avec des signes de ponctuation pour qu'ils correspondent à la façon dont treeje le pense, il y a plus dans l'histoire, comme la ponctuation supprimée des chaînes de comparaison ou quelque chose comme ça. Je peux dire que le /caractère doit être défini comme le caractère le plus bas de la séquence d'assemblage, quoi qu'il en soit.
— WinEunuuchs2Unix
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.