Немає вагомих причин, чому
[[ $a = a|b ]]
Повідомте про помилку, а не перевіряти, чи є $ a a|bрядком, а [[ $a =~ a|b ]]помилка не повертається.
Єдина причина полягає в тому, що |загалом (зовні і всередині [[ ... ]]) особливий характер. У такому [[ $a =положенні bashочікує тип токена, який є звичайним WORD, як аргументи або цілі перенаправлення в звичайному командному рядку оболонки (але так, як якщо б extglobпараметр був увімкнений з bash 4.1).
( СЛОВО тут я маю на увазі слово в гіпотетичній граматиці оболонки, як те, що описується специфікацією POSIX , тобто те, що оболонка розбиратиметься як один маркер у простому командному рядку оболонки, а не інше визначення слів, як англійська один з послідовності букв або послідовності , які не є інтервали між знаками. foo"bar baz", $(echo x y), два таких СЛОВО с).
У звичайному командному рядку оболонки:
echo a|b
Є чи echo aконвеєр b. a|bце не СЛОВО , це три лексеми: a СЛОВ , |лексема та маркер b WORD .
При використанні в [[ $a = a|b ]], bashочікує WORD , які він отримує ( a), але потім знаходить несподіваний |маркер , який викликає помилку.
Цікаво, bashщо не скаржиться на:
[[ $a = a||b ]]
Оскільки тепер це aмаркер, за яким слідує ||маркер, після чого bвін розбирається так само, як:
[[ $a = a || b ]]
Що є тестуванням того, що $aє aабо що bрядок не порожній.
Тепер у:
[[ $a =~ a|b ]]
bashне може мати одне і те ж правило розбору Наявність того ж правила розбору означатиме, що вищезгадане призведе до помилки і що вам потрібно буде цитувати це, |щоб переконатися a|b, що це одне СЛОВ . Але, починаючи з bash 3.2, якщо ви робите:
[[ $a =~ 'a|b' ]]
Це вже не збігається проти a|bрегулярного виразу, але проти a\|bрегулярного. Тобто, котирування оболонки має побічний ефект від усунення особливого значення операторів regexp. Це особливість, тому поведінка схожа на таку [[ $a = "?" ]], але шаблони підстановок (використовувані в [[ $a = pattern ]]) є оболонними WORDS (наприклад, використовуються в глобусах), тоді як регулярні вирази - ні.
Таким чином , bashмає розглядати всі розширені оператори регулярних виразів, які в іншому випадку зазвичай спеціальні символи оболонки , такі як |, (, )інакше при розборі аргументу =~оператора.
Все-таки зауважте, що поки
[[ $a =~ (ab)*c ]]
зараз працює,
[[ $a =~ [)}] ]]
не робить. Тобі потрібно:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Який у попередніх версіях bashневірно відповідав би косому. Це було виправлено, але
[[ $a =~ [^]')'] ]]
Чи має НЕ відповідати на зворотної косої межі , як це слід, наприклад. Тому що bashне в змозі зрозуміти , що )знаходиться в дужках, тому уникає )привести в [^]\)]регулярному виразі, що збігаються з будь-якого символу , але ], \і ).
ksh93 На цьому фронті є набагато гірші помилки.
В zsh, це звичайне слово оболонки, яке очікується, і цитування операторів regexp не впливає на значення операторів regexp.
[[ $a =~ 'a|b' ]]
Збігається з a|bрегулярним виразом.
Це означає , що =~також можуть бути додані до [/ testкоманді:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(також працюйте yash. =~Потрібно вказати, zshяк там =somethingє спеціальний оператор оболонки).
bash 3.1 раніше поводився так zsh. Він змінився в 3.2, імовірно, щоб узгодитись ksh93(навіть незважаючи bashна те, що вперше з'явилася оболонка [[ =~ ]]), але ви все одно можете зробити BASH_COMPAT=31або shopt -s compat31повернутися до попередньої поведінки (за винятком того, що поки [[ $a =~ a|b ]]поверне помилку в bash3.1, вона більше не працює в bash -O compat31нових версіях bash).
Сподіваюсь, це пояснює, чому я сказав, що правила є заплутаними і чому:
[[ $a =~ $var ]]
допомагає в тому числі при переносимості на інші оболонки.
|спеціальний) знаходиться на за замовчуванням в правій частині[[ $var = $pattern ]]. Було б цікаво виділити версії таshoptконфігурації опцій, де спостерігається така поведінка - якщо це лише ті, деextglobввімкнено, або за замовчуванням, або за явну конфігурацію, ну, ми є.