Bash выражение regex if

Что я сделал здесь неправильно?

Попытка сопоставить любую строку, содержащую пробелы, строчные, прописные или цифры. Специальные символы тоже были бы хороши, но я думаю, что для этого требуется экранирование определенных символов.

TEST="THIS is a TEST title with some numbers 12345 and special char *&^%$#"

if [[ "$TEST" =~ [^a-zA-Z0-9\ ] ]]; then BLAH; fi

Это, очевидно, только тесты для верхних, нижних, чисел и пробелов. Не работает.

* ОБНОВЛЕНИЕ *

Думаю, я должен был быть более конкретным. Вот реальная строка кода.

if [[ "$TITLE" =~ [^a-zA-Z0-9\ ] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; fi

* ОБНОВЛЕНИЕ *

./anm.sh: line 265: syntax error in conditional expression
./anm.sh: line 265: syntax error near `&*#]'
./anm.sh: line 265: `  if [[ ! "$TITLE" =~ [a-zA-Z0-9 $%^\&*#] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; return; fi'

Ответ 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: если вы хотите включить ] в класс символов, он должен идти в начале. - может идти в начале или в конце, поэтому, если вам нужны как ], так и -, вам нужно начинать с ] и заканчивать на -, приводя к регулярному выражению "Я знаю, что я делаю": [][-])

Ответ 2

Я бы предпочел использовать [:punct:] для этого. Кроме того, a-zA-Z09-9 может быть просто [:alnum:]:

[[ $TEST =~ ^[[:alnum:][:blank:][:punct:]]+$ ]]

Ответ 3

В случае, если кому-то нужен пример с использованием переменных...

#!/bin/bash

# Only continue for 'develop' or 'release/*' branches
BRANCH_REGEX="^(develop$|release//*)"

if [[ $BRANCH =~ $BRANCH_REGEX ]];
then
    echo "BRANCH '$BRANCH' matches BRANCH_REGEX '$BRANCH_REGEX'"
else
    echo "BRANCH '$BRANCH' DOES NOT MATCH BRANCH_REGEX '$BRANCH_REGEX'"
fi