【问题标题】:Regex matching in a Bash if statementBash if 语句中的正则表达式匹配
【发布时间】:2013-09-13 15:13:34
【问题描述】:

我在这里做错了什么?

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

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'

【问题讨论】:

  • 您实际使用的是哪个外壳? /bin/sh? /bin/bash? /bin/csh?
  • 将正则表达式放在变量中更安全。 re='...whatever...'; [[ $string =~ $re ]](不带引号——这是一种罕见的情况,他们会破坏没有引号的东西)。
  • 请在作业两边加上单引号。双引号不能正确保护特殊字符。
  • 非常感谢查尔斯!不把它放在一个变量中还是可以的,但它绝对不能被引用!例如:[[ $var =~ .* ]] 匹配正则表达式 .*(任何东西)。我猜如果你使用引号,引号本身被认为是正则表达式的一部分......
  • 我发现的问题总结:(1.) 如果您需要正则表达式匹配,请在双平方表达式中使用单引号 pattern='^hello[0-9]*$' (2.) 将模式保存在变量中,不要引用模式 因为引用禁用正则表达式模式匹配。 (即表达式 [[ "$x" =~ $pattern ]] 将使用正则表达式匹配,而表达式 [[ "$x" =~ "$pattern" ]] 禁用正则表达式匹配,等效于 [[ "$x" == "$pattern" ]])。

标签: regex bash if-statement


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 只想指出 "!~ 是“不匹配”运算符" 是不正确的。使用if ! [[ $x =~ $y ]]if [[ ! $x =~ $y ]]
    • shellchecker 不同意...SC2076: Don't quote rhs of =~, it'll match literally rather than as a regex.
    • @leonard:这与我的声明“你不能引用变量扩展”和评论“这不起作用”有什么不同?有什么不清楚的地方?
    • @jinbeomhong:表达式本身像往常一样使用空格分隔成单词。但是参数和命令扩展不是分词的。
    • @jinbeomhong:我并没有说与 bash 手册有什么不同。 “[[]] 之间的单词”从程序文本中解析出来,就像命令行被解析成单词一样。不过,与命令行不同的是,单词在展开后不会被拆分。
    【解决方案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
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 看来该模式必须至少以^ 开头并以美元符号$ 结尾才能工作。这是这样做的唯一方法,这样得到的真值对我来说是正确的。 (???)
      • 我仍然设法在 javascript 中弄错了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-26
      • 1970-01-01
      • 2019-12-11
      相关资源
      最近更新 更多