Вираз дужки (без діапазонів), що відповідає несподіваному символу в баші


20

Я використовую bash на Linux. Я отримую успіх з наступного if заяви, але чи не повинен це повернути код відмови?

if [[  = [⅕⅖⅗] ]] ; then echo yes ; fi

Квадрат НЕ дорівнює жодному із символів, тому я не бачу, чому я отримую код успіху.

Для мене важливо зберегти подвійні дужки в моєму випадку.

Чи є якийсь інший спосіб зробити діапазон у цьому сценарії чи які ще пропозиції?


2
Можливо, це наслідок усіх тих символів, які мають не визначений порядок сортування у вашій мові (і таким чином сортування того ж). Дивіться поточну дискусійну дискусію в групі Остіна . Змініть локаль на C, щоб виправити його .
Стефан Шазелас

1
Вибачте, Cтут не робитимуть, оскільки це не однобайтові символи. C.UTF-8зробить там, де є можливість.
Стефан Шазелас

11
Вітаємо, вам вдалося викликати Стефана, який тримав нитку Austin Group у першому запитанні. Це повинно бути варте як мінімум ⅗ Інтернету. Або ⅘ або навіть ■ Інтернети, як мабуть, ті самі. Ласкаво просимо до Unix & Linux , і будь-ласка, продовжуйте ставити цікаві запитання.
дероберт

Відповіді:


29

Це наслідок тих символів, що мають однаковий порядок сортування.

Ви також це помітите

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_COLLATEC, який би працював на системах GNU, але не обов'язково для інших, де він не міг вказати порядок сортування багатобайтового символу.


Один урок цього полягає в тому, що рівність не є настільки чітким поняттям, як можна було б очікувати, коли мова йде про порівняння рядків. Рівність може означати від найсуворішої до найменш суворої.

  1. Однакова кількість байтів і всі складові байти мають однакове значення.
  2. Однакова кількість символів і всі символи однакові (наприклад, посилайтеся на ту саму кодову точку в поточній діаграмі).
  3. Дві рядки мають той самий порядок сортування, що і за алгоритмом зіставлення локалі (тобто, ні 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.


Ще один поширений випадок, коли 1 і 2 відрізняються, це Unicode з такими речами, як поєднання символів.
Жил "ТАК - перестань бути злим"

@Gilles, що поєднує персонажів, є своїми персонажами. Поєднання утворює графему / клітинку, але все ще складається з кількох символів. é (U + 00E9) та é (e з наступним U + 0301) - це та сама графема, але дві різні послідовності символів (принаймні з точки зору API POSIX). За 1 і 2 вони були б різними. До 3, вони могли б вважати тим самим, якби у U + 0301 були встановлені всі ваги зіставлення на "IGNORE", але це, як правило, не так, як звичайно хочеться визначитися з порядком діакритики.
Стефан Шазелас

Зазвичай бажано вважати éі бути однаковою струною, але ні e. Поняття POSIX про порядок порівняння рідко має рацію, воно занадто сильно засноване на символах і не враховує найпоширеніших способів сортування рядків (наприклад, французькі словники не використовують лексикографічний порядок для сортування слів: вони роблять перший лексикографічний пропуск із наголошеними ігнорованими та потім використовуйте наголоси для вирішення зв’язків).
Жиль "ТАК - перестань бути злим"

@Gilles, так. Ось чому я б сказав, що ті символи, які мають однаковий порядок сортування (навмисно) у локаціях glibc, мають мало сенсу. Зрештою, проти цього, як правило, вирішується шляхом перетворення рядків спочатку, як канонічна декомпозиція (подібно до перетворення в нижній регістр спочатку, коли ви хочете зробити нечутливе до регістру сортування / відповідність). Дивіться також посібник ICU для отримання гарних посилань на цю тему.
Стефан Шазелас

@Gilles, алгоритм зіставлення локальної ваги POSIX може робити це сортування у французькому словнику. Ось так працюють ваги. Перший прохід використовує первинні ваги (де e і é (і E і É) однакові, а комбінуючий гострий наголос ігнорується) другий прохід (якщо рівний) перевіряє наголоси, 3-й пропуск з великої літери ...
Stéphane Chazelas

-3

Ви робите це неправильно, =і ==не однакові.

Спробуйте такі приклади:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi

1
Що це не так. POSIX вказує, що оператор =повинен використовуватися для перевірки рівності. Проблема - відсутні котирування, а не оператор.
scai

1
Також man bashв [[розділі сказано : "Оператор = еквівалентний ==".
michas

1
@scai, POSIX не вказує [[...]]оператора. І = і == однакові в оболонках, якщо це було реалізовано (ksh / bash / zsh) і для відповідності шаблону, а не рівності.
Стефан Шазелас

Якщо порівнювати з шаблоном, шаблон не повинен котируватися, інакше він приймається як буквальний рядок, звідси і "ні" в першому тесті.
xhienne
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.