在Bash if语句中匹配正则表达式

Regex matching in a Bash if statement

我在这里做错什么了?

试图匹配包含空格、小写、大写或数字的任何字符串。特殊字符也不错,但我认为这需要转义某些字符。

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

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

显然,这只测试上限、下限、数字和空格。但是不起作用。

*更新*

我想我应该更具体一些。这是实际的代码行。

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

*更新*

1
2
3
./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'


关于Bash的[[ ]]结构,有一些重要的事情需要了解。第一:

Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.

第二件事:

An additional binary operator, ‘=~’, is available,... the string to the right of the operator is considered an extended regular expression and matched accordingly... Any part of the pattern may be quoted to force it to be matched as a string.

因此,=~两侧的$v将扩展到该变量的值,但结果不会是单词split或路径名扩展。换句话说,在左侧不引用变量展开是完全安全的,但是您需要知道,变量展开将在右侧发生。

所以如果你写:[[ $x =~ [$0-9a-zA-Z] ]],右边regex里面的$0会在regex解释之前被扩展,这可能会导致regex编译失败(除非$0的扩展以一个ASCII值小于一个数字的数字或标点符号结束)。如果你引用右手边的话,比如[[ $x =~"[$0-9a-zA-Z]" ]],那么右手边将被视为一个普通的字符串,而不是regex($0仍然会被扩展)。在这种情况下,你真正想要的是[[ $x =~ [\$0-9a-zA-Z] ]]

类似地,[[]]之间的表达式在regex被解释之前被分解为单词。所以regex中的空格需要转义或引用。如果要匹配字母、数字或空格,可以使用:[[ $x =~ [0-9a-zA-Z\ ] ]]。其他类似的字符也需要转义,比如#,如果不引用,它将开始注释。当然,您可以将模式放入变量中:

1
2
pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...

对于包含大量需要转义或引用以通过bash的lexer的字符的regex,许多人喜欢这种风格。但要注意:在这种情况下,不能引用变量展开:

1
2
# This doesn't work:
if [[ $x =~"$pat" ]]; then ...

最后,我认为您要做的是验证变量是否只包含有效字符。执行此检查的最简单方法是确保它不包含无效字符。换句话说,像这样的表达:

1
2
valid='0-9a-zA-Z $%&#' # add almost whatever else you want to allow to the list
if [[ ! $x =~ [^$valid] ]]; then ...

!否定了测试,将其转换为"不匹配"运算符,[^...]regex字符类表示"...以外的任何字符"。

参数扩展和regex运算符的结合可以使bash正则表达式语法"几乎可读",但仍然存在一些问题。(不总是这样吗?)一个是你不能把]放进$valid中,即使$valid被引用了,除了一开始。(这是一个posix regex规则:如果您想在字符类中包含],就需要在开始处进行。-可以从开始到结束,所以如果你既需要]又需要-的话,你需要从]开始到-结束,这就导致了regex"我知道我在做什么"表情:[][-]


如果有人想要一个使用变量的例子…

1
2
3
4
5
6
7
8
9
10
11
#!/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


我宁愿用[:punct:]来做这个。另外,a-zA-Z09-9可能只是[:alnum:]而已:

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