Почему сортировка ls игнорирует не алфавитно-цифровые символы?

25

При сортировке имен файлов lsигнорирует такие символы, как -,_. Я ожидал, что он будет использовать эти символы в сортировке.

Пример:

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

Теперь отобразите эти файлы с помощью ls -1:

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

То, что я ожидал, было что-то вроде этого:

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

т.е. я ожидал, что при сортировке будут учитываться не алфавитно-цифровые символы.

Кто-нибудь может объяснить это поведение? Это поведение предписано стандартом? Или это связано с кодировкой UTF-8?

Обновление: Похоже, это связано с сортировкой 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 и ASCII идентичны, если все, что вы используете, это первые 128 кодовых точек (как в вашем примере). Что произойдет, если вы делаете LC_COLLATE=C ls?
Алексиос
Проблема не в том, что ASCII и UTF-8 идентичны, а в том, что UTF-8 имеет свои собственные правила сортировки (сортировки).
Даниэль Куллманн
1
Да, это правда, что [_-,.]они группируются и почему-то почти игнорируются. Я не знаю точно , как или где определяется такая сверка, но это должно быть проблемой сортировки, так просто, и только, изменяя параметры сортировки на C (через LC_COLLATE=C ls -l) достаточно , чтобы дать вам порядок сортировки вы ожидали (при условии , LC_ALLявляется не переопределять LC_COLLATE). Это относится ко всему диапазону символов в базовой многоязычной плоскости Unicode ... Я отредактировал свой ответ, включив в него пример сценария, который это подтверждает ...
Peter.O
если вам не нравится, как это работает, вы можете создать псевдоним и поместить его в свой ~ / .profile: alias ls = 'LC_COLLATE = C ls' </ kbd>
jippie

Ответы:

10

Это не имеет ничего общего с кодировкой. Скорее, именно язык определяет порядок сопоставления. Libc проверяет язык, представленный в $LC_COLLATE/ $LC_ALL/, $LANGи ищет правила сопоставления (например, /usr/share/i18n/locales/*для GLibC) и упорядочивает текст в соответствии с указаниями.

Игнасио Васкес-Абрамс
источник
К вашему сведению: это сложнее, чем это. Если бы вы использовали, strcollнапример, вы бы увидели, что что-то вроде aasa.cбудет отсортировано выше aas.c.
Дон Скотт
12

РЕДАКТИРОВАТЬ: Добавлен тест для данных, отсортированных с LC_COLLATE = C


Последовательность сортировки по умолчанию обрабатывает эти символы «типа пунктуации» как имеющие одинаковое значение .. Use LC_COLLATE=Cдля обработки их в порядке кодировки.

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

Выход

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

В следующем коде проверяются все действительные символы UTF-8 в базовой многоязычной плоскости (за исключением \ x00 и \ x0a ; для простоты).
Он сравнивает файл в известной (сгенерированной) возрастающей последовательности с этим файлом, случайно отсортированным, а затем снова сортируется с LC_COLLATE = С. Результат показывает, что последовательность C идентична исходной сгенерированной последовательности.

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

Выход:

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

cmp $?=0
Peter.O
источник
2
Где это задокументировано? Это часть стандарта Unicode?
Даниэль Куллманн
2
На самом деле, они не получают одинаковое значение; эти символы просто игнорируются при сортировке. Если бы они рассматривались как имеющие одинаковое значение, порядок сортировки a_1 a2 a_2был бы невозможен.
Даниэль Куллманн
+1 за вашу тяжелую работу и пример кода. После многих часов сортировки имен каталогов с пунктуацией в соответствии с тем, treeкак это происходит, я думаю, что в истории есть нечто большее, например, удаление знаков препинания из строк сравнения или что-то в этом роде. Я могу сказать, что /символ должен быть установлен как самый низкий символ в последовательности сортировки, независимо от того, что еще.
WinEunuuchs2Unix