127

我在这里做错了什么?

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

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

4 回答 4

223

[[ ]]关于 bash 的构造,有几件重要的事情需要了解。首先:

和之间的单词不进行分词和路径名[[扩展]];执行波浪号扩展、参数和变量扩展、算术扩展、命令替换、进程替换和引号删除。

第二件事:

可以使用附加的二元运算符“=~”,...运算符右侧的字符串被视为扩展正则表达式并进行相应匹配...可以引用模式的任何部分以强制匹配作为一个字符串

因此,$v在 的任一侧=~都将扩展为该变量的值,但结果不会是单词拆分或路径名扩展。换句话说,在左侧不加引号的变量扩展是完全安全的,但您需要知道变量扩展将发生在右侧。

所以如果你写: [[ $x =~ [$0-9a-zA-Z] ]]$0右边的正则表达式内部会在正则表达式被解释之前被扩展,这可能会导致正则表达式无法编译(除非扩展以$0ascii值小于的数字或标点符号结尾一个数字)。如果您引用右侧的 like-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 词法分析器的字符的正则表达式,许多人更喜欢这种风格。但请注意:在这种情况下,您不能引用变量扩展:

# 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 正则表达式规则:如果你想包含]在一个字符类中,它需要在开头。-可以在开头或结尾,所以如果你需要两个]and -,你需要以 开头]和结尾-,导致正则表达式“我知道我在做什么”表情[][-]:)

于 2013-09-10T04:41:01.100 回答
46

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

#!/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
于 2015-01-26T15:16:27.510 回答
13

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

[[ $TEST =~ ^[[:alnum:][:blank:][:punct:]]+$ ]]
于 2013-09-10T04:03:48.703 回答
3

或者您可能正在查看这个问题,因为您碰巧像我一样犯了一个愚蠢的错字并将 =~ 反转为 ~=

于 2020-12-02T06:40:20.260 回答