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

时间:2013-09-10 02:45:53

标签: regex bash if-statement

我在这里做错了什么?

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

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'

4 个答案:

答案 0 :(得分:125)

关于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的词法分析器进行转义或引用,很多人都喜欢这种风格。但要注意:在这种情况下,不能引用变量扩展:

# 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 ...

!否定测试,将其变为“不匹配”运算符,[^...]正则表达式字符类表示“...以外的任何字符”。

参数扩展和正则表达式运算符的组合可以使bash正则表达式语法“几乎可读”,但仍然存在一些问题。 (不是总是存在吗?)一个是你无法将]放入$valid,即使引用$valid,除非在开头。 (这是一个Posix正则表达式规则:如果你想在一个字符类中包含],它需要在开头。-可以在开头或结尾,所以如果你需要两个{ {1}}和],您需要从-开始,以]结束,从而导致正则表达式“我知道我在做什么”表情符号:-

答案 1 :(得分: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

答案 2 :(得分:10)

我更愿意使用[:punct:]。此外,a-zA-Z09-9可能只是[:alnum:]

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

答案 3 :(得分:0)

或者您可以像我一样做一个愚蠢的错字,然后将=〜反转为〜=