Ответ 1
Есть несколько важных вещей, которые нужно знать о конструкции bash [[ ]]
. Первое:
Разделение слов и расширение имени пути не выполняются над словами между
[[
и]]
; расширение тильды, расширение параметров и переменных, арифметическое расширение, подстановка команд, замещение процессов и удаление цитат.
Второе:
Доступен дополнительный двоичный оператор, '= ~,... строка справа от оператора рассматривается как расширенное регулярное выражение и соответствует соответственно... Любая часть шаблона может быть указана в заставьте его соответствовать строке.
Следовательно, $v
по обе стороны от =~
будет расширен до значения этой переменной, но результат не будет разделен по слову или расшифрован по пути. Другими словами, совершенно безопасно оставлять переменные расширения без кавычек с левой стороны, но вам нужно знать, что переменные расширения будут выполняться с правой стороны.
Итак, если вы пишете: [[ $x =~ [$0-9a-zA-Z] ]]
, $0
внутри регулярного выражения справа будет разворачиваться до того, как будет интерпретировано регулярное выражение, что, вероятно, вызовет сбой компиляции регулярного выражения (если расширение $0
не будет завершено с цифрой или символом пунктуации, значение ascii которого меньше цифры). Если вы укажете правую часть как-так [[ $x =~ "[$0-9a-zA-Z]" ]]
, тогда правая часть будет рассматриваться как обычная строка, а не регулярное выражение (и $0
все равно будет расширено). В этом случае вам действительно нужно [[ $x =~ [\$0-9a-zA-Z] ]]
Аналогично, выражение между [[
и ]]
разбивается на слова перед интерпретацией регулярного выражения. Поэтому пробелы в регулярном выражении должны быть экранированы или процитированы. Если вы хотите совместить буквы, цифры или пробелы, вы можете использовать: [[ $x =~ [0-9a-zA-Z\ ] ]]
. Другие символы аналогичным образом должны быть экранированы, например #
, которые будут запускать комментарий, если не цитируются. Конечно, вы можете поместить шаблон в переменную:
pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...
Для регулярных выражений, которые содержат много символов, которые нужно было бы экранировать или процитировать, чтобы пройти через bash lexer, многие предпочитают этот стиль. Но будьте осторожны: в этом случае вы не можете процитировать расширение переменной:
# This doesn't work:
if [[ $x =~ "$pat" ]]; then ...
Наконец, я думаю, что вы пытаетесь проверить, что переменная содержит только действительные символы. Самый простой способ сделать эту проверку - убедиться, что она не содержит недопустимый символ. Другими словами, выражение, подобное этому:
valid='0-9a-zA-Z $%&#' # add almost whatever else you want to allow to the list
if [[ ! $x =~ [^$valid] ]]; then ...
!
отменяет тест, превращая его в оператор "не соответствует", а класс символов [^...]
regex означает "любой символ, отличный от ...
".
Комбинация расширений параметров и операторов регулярных выражений может сделать синтаксис регулярных выражений bash "почти читаемым", но все же есть некоторые ошибки. (Разве это не всегда?) Одно дело, что вы не могли поместить ]
в $valid
, даже если $valid
были указаны, кроме как в самом начале. (Правило регулярного выражения Posix: если вы хотите включить ]
в класс символов, он должен идти в начале. -
может идти в начале или в конце, поэтому, если вам нужны как ]
, так и -
, вам нужно начинать с ]
и заканчивать на -
, приводя к регулярному выражению "Я знаю, что я делаю": [][-]
)