Warum ignoriert die Sortierung nicht-alphanumerische Zeichen?

25

lsIgnoriert beim Sortieren von Dateinamen Zeichen wie -,_. Ich hatte erwartet, dass diese Zeichen auch beim Sortieren verwendet werden.

Ein Beispiel:

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

Zeigen Sie diese Dateien nun an mit ls -1:

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

Was ich erwartet hatte, war ungefähr so:

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

Dh ich habe erwartet, dass die nicht alphanumerischen Zeichen beim Sortieren berücksichtigt werden.

Kann jemand dieses Verhalten erklären? Ist dieses Verhalten durch einen Standard vorgeschrieben? Oder liegt das daran, dass die Codierung UTF-8 ist?

Update: Es scheint, dass dies mit der UTF-8-Sortierung zusammenhängt:

$ 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
quelle
2
UTF-8 und ASCII sind identisch, wenn Sie nur die ersten 128 Codepunkte verwenden (wie in Ihrem Beispiel). Was passiert, wenn Sie es tun LC_COLLATE=C ls?
Alexios
Das Problem ist nicht, dass ASCII und UTF-8 identisch sind, sondern dass UTF-8 seine eigenen Sortierregeln hat.
Daniel Kullmann
1
Ja, es ist wahr, [_-,.]dass gruppiert und irgendwie teilweise ignoriert werden. Ich weiß nicht genau, wie oder wo eine solche Kollatierung definiert ist, aber es muss ein Kollatierungsproblem sein, da es ausreicht , die Kollatierung einfach und ausschließlich in C (Via LC_COLLATE=C ls -l) zu ändern , um Ihnen die erwartete Sortierreihenfolge zu geben (vorausgesetzt, dies LC_ALList nicht überschreiben LC_COLLATE). Dies gilt für den gesamten Bereich der Zeichen in der mehrsprachigen Unicode-Grundebene ... Ich habe meine Antwort so bearbeitet, dass sie ein Beispielskript enthält, das dies bestätigt ...
Peter.O
Wenn Ihnen die Funktionsweise nicht gefällt, können Sie einen Alias ​​erstellen und in Ihr ~ / .profile einfügen: alias ls = 'LC_COLLATE = C ls' </ kbd>
jippie

Antworten:

10

Dies hat nichts mit dem Zeichensatz zu tun. Es ist vielmehr die Sprache, die die Sortierreihenfolge bestimmt. Die libc prüft die Sprache in präsentierten $LC_COLLATE/ $LC_ALL/ $LANGund sieht auf seine Sortierregeln (zB /usr/share/i18n/locales/*für glibc) und Aufträge den Text , wie verwiesen.

Ignacio Vazquez-Abrams
quelle
Zu Ihrer Information: Es ist komplizierter. Wenn man strcollzum Beispiel verwenden würde, würde man sehen, dass so etwas aasa.coben sortiert wäre aas.c.
Don Scott
12

EDIT: Test für mit LC_COLLATE = C sortierte Daten hinzugefügt


Die Standard-Sortierfolge behandelt diese "Interpunktionstyp" -Zeichen als gleichwertig Use LC_COLLATE=C, um sie in Codepunktreihenfolge zu behandeln.

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

Ausgabe

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

Der folgende Code testet alle gültigen UTF-8-Zeichen in der mehrsprachigen Basisebene (mit Ausnahme von \ x00 und \ x0a ; zur Vereinfachung).
Er vergleicht eine Datei in einer bekannten (generierten) aufsteigenden Reihenfolge mit dieser Datei, die zufällig sortiert und dann erneut mit sortiert wird LC_COLLATE = C. Das Ergebnis zeigt, dass die C- Sequenz mit der ursprünglich erzeugten Sequenz identisch ist.

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

Ausgabe:

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

cmp $?=0
Peter.O
quelle
2
Wo ist das dokumentiert? Gehört das zum Unicode-Standard?
Daniel Kullmann
2
Eigentlich bekommen sie nicht den gleichen Wert; Diese Zeichen werden beim Sortieren einfach ignoriert. Wenn sie als gleichwertig behandelt a_1 a2 a_2würden, wäre die Sortierreihenfolge unmöglich.
Daniel Kullmann
+1 für Ihre harte Arbeit und Beispielcode. Nach vielen Stunden, in denen die Verzeichnisnamen mit Interpunktion sortiert wurden, um der Art und Weise zu entsprechen, treegibt es meiner Meinung nach mehr an der Geschichte als die Interpunktion, die aus Vergleichszeichenfolgen entfernt wird, oder so etwas. Ich kann sagen, dass das /Zeichen als das niedrigste Zeichen in der Sortierfolge festgelegt werden muss, egal was sonst.
WinEunuuchs2Unix