在 Bash 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'
321254 次浏览

我更喜欢使用 [:punct:]。而且,a-zA-Z09-9可以只是 [:alnum:]:

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

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

[[]]之间的单词不执行分词和路径名扩展,执行波浪线扩展、参数和变量扩展、算术扩展、指令替代扩展、进程替换和报价删除。

第二件事:

可以使用另外一个二进制运算符‘ = ~’,... 运算符右边的字符串被视为扩展正则表达式,并相应地匹配... 可以引用模式的任何部分来强制它作为字符串进行匹配

因此,=~两边的 $v将被扩展为该变量的值,但是结果不会是字分割或路径名扩展。换句话说,在左边不引用变量扩展是完全安全的,但是您需要知道变量扩展将发生在右边。

因此,如果你写: [[ $x =~ [$0-9a-zA-Z] ]],右边正则表达式中的 $0将在正则表达式被解释之前展开,这可能会导致正则表达式无法编译(除非 $0的展开以一个数字或标点符号结束,其 ascii 值小于一个数字)。如果您引用右侧如-so [[ $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 ...

!否定测试,将其转换为“不匹配”操作符,而 [^...]正则表达式字符类表示“除 ...以外的任何字符”。

参数展开和正则表达式操作符的组合可以使 bash 正则表达式语法“几乎可读”,但仍然存在一些陷阱。(不是一直都有吗?)一个是,你不能把 ]$valid,即使 $valid被引用,除非在最开始。(这是 Posix 正则表达式规则: 如果你想在字符类中包含 ],它需要从头开始。-可以在开头或结尾,所以如果你同时需要 ]-,你需要从 ]开始,以 -结束,导致 regex“我知道我在做什么”表情符号: [][-])

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

#!/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

或者你正在看这个问题,因为你碰巧像我一样犯了一个愚蠢的错误,把 = ~ 反转成了 ~ =