Dlaczego sortowanie ls ignoruje znaki niealfanumeryczne?

25

Podczas sortowania nazw plików lsignoruje znaki takie jak -,_. Spodziewałem się, że użyje również tych znaków do sortowania.

Przykład:

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

Teraz wyświetl te pliki za pomocą ls -1:

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

Spodziewałem się czegoś takiego:

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

tj. spodziewałem się, że znaki niealfanumeryczne będą brane pod uwagę podczas sortowania.

Czy ktoś może wyjaśnić to zachowanie? Czy takie zachowanie jest wymagane przez standard? A może jest to spowodowane kodowaniem UTF-8?

Aktualizacja: Wygląda na to, że jest to związane z sortowaniem 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
źródło
2
UTF-8 i ASCII są identyczne, jeśli wszystko, czego używasz, to pierwsze 128 współrzędnych kodowych (co jest twoim przykładem). Co się stanie, jeśli to zrobisz LC_COLLATE=C ls?
Alexios
Problem nie polega na tym, że ASCII i UTF-8 są identyczne, a raczej, że UTF-8 ma własne reguły sortowania (sortowania).
Daniel Kullmann
1
Tak, to prawda, że [_-,.]są grupowane i częściowo ignorowane. Nie wiem dokładnie, jak i gdzie takie sortowanie jest zdefiniowane, ale musi to być problem z sortowaniem, ponieważ po prostu i tylko zmiana sortowania na C (via LC_COLLATE=C ls -l) wystarczy, aby dać ci porządek sortowania, którego się spodziewałeś (zakładając, że LC_ALLjest to nie zastępuje LC_COLLATE). Odnosi się to do całego zakresu znaków w wielojęzycznym samolocie podstawowym Unicode ... Zredagowałem swoją odpowiedź, aby dołączyć przykładowy skrypt, który to
potwierdza
jeśli nie podoba ci się, jak to działa, możesz utworzyć alias i umieścić go w swoim ~ / .profile: alias ls = 'LC_COLLATE = C ls' </kbd>
jippie

Odpowiedzi:

10

To nie ma nic wspólnego z zestawem znaków. Raczej to język określa porządek sortowania. Libc sprawdza język przedstawiony w $LC_COLLATE/ $LC_ALL/ $LANGi sprawdza jego zasady sortowania (np. /usr/share/i18n/locales/*Dla GLibC) i porządkuje tekst zgodnie z zaleceniami.

Ignacio Vazquez-Abrams
źródło
FYI: To bardziej skomplikowane niż to. Gdyby strcollna przykład użyć , zobaczyłbyś, że coś takiego aasa.cbyłoby posortowane powyżej aas.c.
Don Scott
12

EDYCJA: Dodano test danych posortowanych za pomocą LC_COLLATE = C


Domyślna kolejność zestawiania polega na traktowaniu znaków „interpunkcyjnych” jako Use LC_COLLATE=Cmających jednakową wartość .. aby traktować je w kolejności współrzędnych kodowych.

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

Wydajność

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

Poniższy kod testuje wszystkie poprawne znaki UTF-8 w podstawowej płaszczyźnie wielojęzycznej (z wyjątkiem \ x00 i \ x0a ; dla uproszczenia).
Porównuje plik w znanej (generowanej) sekwencji rosnącej z tym plikiem losowo posortowanym, a następnie ponownie posortowanym za pomocą LC_COLLATE = C. Wynik pokazuje, że sekwencja C jest identyczna z oryginalnie wygenerowaną sekwencją.

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

Wydajność:

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

cmp $?=0
Peter.O
źródło
2
Gdzie to jest udokumentowane? Czy to część standardu Unicode?
Daniel Kullmann
2
W rzeczywistości nie mają takiej samej wartości; te znaki są po prostu ignorowane podczas sortowania. Gdyby były traktowane jako mające taką samą wartość, porządek sortowania a_1 a2 a_2byłby niemożliwy.
Daniel Kullmann
+1 za ciężką pracę i przykładowy kod. Po wielu godzinach sortowania nazw katalogów ze znakami interpunkcyjnymi zgodnymi ze sposobem, w jaki treeto robi, myślę, że w tej historii jest coś więcej, np. Usuwanie interpunkcji z ciągów porównawczych lub coś w tym rodzaju. Mogę powiedzieć, że /znak musi być ustawiony jako najniższy znak w sekwencji zestawiania, bez względu na wszystko.
WinEunuuchs2Unix