Немає вагомих причин, чому
[[ $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 ]]
поверне помилку в bash
3.1, вона більше не працює в bash -O compat31
нових версіях bash
).
Сподіваюсь, це пояснює, чому я сказав, що правила є заплутаними і чому:
[[ $a =~ $var ]]
допомагає в тому числі при переносимості на інші оболонки.
|
спеціальний) знаходиться на за замовчуванням в правій частині[[ $var = $pattern ]]
. Було б цікаво виділити версії таshopt
конфігурації опцій, де спостерігається така поведінка - якщо це лише ті, деextglob
ввімкнено, або за замовчуванням, або за явну конфігурацію, ну, ми є.