Там нет веских причин, почему
[[ $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 СЛОВА .
При использовании в [[ $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регулярным выражением. То есть кавычки оболочки имеют побочный эффект удаления специального значения операторов регулярных выражений. Это особенность, поэтому поведение аналогично тому [[ $a = "?" ]], но шаблоны подстановочных знаков (используемые в [[ $a = pattern ]]) являются СЛОВАМИ оболочки (например, используются в globs), а регулярные выражения - нет.
Таким образом , bashдолжно рассматривать все расширенные операторы регулярных выражений, которые в противном случае обычно специальные символы оболочки , такие как |, (, )иначе при разборе аргумента =~оператора.
Тем не менее, обратите внимание, что в то время как
[[ $a =~ (ab)*c ]]
сейчас работает,
[[ $a =~ [)}] ]]
не делает. Тебе нужно:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Который в предыдущих версиях bashнекорректно совпадал с обратной косой чертой. Это было исправлено, но
[[ $a =~ [^]')'] ]]
Имеет ли не соответствовать на обратной косой черты , как это следует, например. Потому что bashне может понять, что )находится в скобках, поэтому избегает, )чтобы привести к [^]\)]регулярному выражению, которое соответствует любому символу, кроме ], \и ).
ksh93 есть гораздо худшие ошибки на этом фронте.
Во- zshпервых, это обычное слово оболочки, которое ожидается, и операторы регулярного выражения в кавычках не влияют на значение операторов регулярного выражения.
[[ $a =~ 'a|b' ]]
Соответствует a|bрегулярному выражению.
Это означает, что =~можно также добавить к команде [/ test:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(также работает в yash. The =~потребности быть процитированные в 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включено, либо по умолчанию, либо в явной конфигурации, ну, вот и мы.