Це наслідок тих символів, що мають однаковий порядок сортування.
Ви також це помітите
sort -u << EOF
■
⅕
⅖
⅗
EOF
повертає лише один рядок.
Або що:
expr ■ = ⅕
повертає true (як вимагає POSIX).
Більшість локалів, що постачаються із системами GNU, мають ряд символів (і навіть послідовностей символів (збірних послідовностей)), що мають однаковий порядок сортування. У випадку тих ■ ⅕⅖⅗, це тому, що порядок не визначений, і ті символи, порядок яких не визначено, в кінцевому підсумку мають однаковий порядок сортування в системах GNU. Є символи, які чітко визначені як такі, що мають такий самий порядок сортування, як Ș і Ş (хоча для мене явно немає (для мене явно) реальної логіки чи послідовності того, як це робиться).
Це джерело досить дивовижної та хитрої поведінки. Я порушив цю проблему зовсім недавно в списку розсилки групи Остін (орган, що стоїть за POSIX та Єдиною специфікацією UNIX), і дискусія триває до 2015-04-03.
У цьому випадку, чи [y]
слід збігатися з тим, x
де x
і y
сортувати те саме, мені незрозуміло, але оскільки думка думки має на меті відповідати елементу, що згортається, це говорить про те, що bash
поведінка очікується.
У будь-якому випадку, я гадаю, [⅕-⅕]
або принаймні [⅕-⅖]
має відповідати ■
.
Ви помітите, що різні інструменти поводяться по-різному. ksh93 поводиться так bash
, GNU grep
чи sed
ні. Деякі інші оболонки мають різну поведінку, деякі люблять yash
ще більше баггі.
Щоб мати послідовну поведінку, вам потрібен локаль, де всі символи сортуються по-різному. Локальний тип C є типовим. Однак набір символів у мові С на більшості систем - ASCII. У системах GNU, як правило, ви маєте доступ до C.UTF-8
локалі, який можна використовувати замість цього для роботи над символом UTF-8.
Так:
(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])
або стандартний еквівалент:
(export LC_ALL=C.UTF-8
case ■ in ([⅕⅖⅗]) true;; (*) false; esac)
має повернути помилкове.
Іншою альтернативою було б встановити лише LC_COLLATE
C, який би працював на системах GNU, але не обов'язково для інших, де він не міг вказати порядок сортування багатобайтового символу.
Один урок цього полягає в тому, що рівність не є настільки чітким поняттям, як можна було б очікувати, коли мова йде про порівняння рядків. Рівність може означати від найсуворішої до найменш суворої.
- Однакова кількість байтів і всі складові байти мають однакове значення.
- Однакова кількість символів і всі символи однакові (наприклад, посилайтеся на ту саму кодову точку в поточній діаграмі).
- Дві рядки мають той самий порядок сортування, що і за алгоритмом зіставлення локалі (тобто, ні a <b, ні b> a не відповідає дійсності).
Тепер для 2 або 3, що передбачає, що обидва рядки містять дійсні символи. У UTF-8 та деяких інших кодуваннях деякі послідовності байтів не утворюють дійсних символів.
1 і 2 не обов'язково є еквівалентними через це або тому, що деякі символи можуть мати більше одного можливого кодування. Типово це стосується кодуючих станів, таких як ISO-2022-JP, де A
їх можна виразити як 41
або 1b 28 42 41
( 1b 28 42
будучи послідовністю перемикання на ASCII, і ви можете вставити скільки завгодно таких, що не змінить), хоча я не очікував, що ці типи кодування все ще використовуються, а інструменти GNU принаймні взагалі не працюють належним чином з ними.
Також майте на увазі, що більшість утиліт, що не належать до GNU, не можуть мати справу зі значенням 0 байт (символ NUL в ASCII).
Яке із цих визначень використовується, залежить від корисності та корисності реалізації чи версії. POSIX не на 100% зрозумілий у цьому. У мові С всі 3 еквівалентні. Поза цим YMMV.