bash 正则表达式带引号?

Posted

技术标签:

【中文标题】bash 正则表达式带引号?【英文标题】:bash regex with quotes? 【发布时间】:2010-09-18 02:30:03 【问题描述】:

以下代码

number=1
if [[ $number =~ [0-9] ]]
then
  echo matched
fi

有效。但是,如果我尝试在正则表达式中使用引号,它会停止:

number=1
if [[ $number =~ "[0-9]" ]]
then
  echo matched
fi

我也试过"\[0-9\]"。我错过了什么?

有趣的是,bash advanced scripting guide 建议这应该可行。

Bash 版本 3.2.39。

【问题讨论】:

ABS 作为不准确(或者,在更好的日子里,仅仅是误导)指导的来源而臭名昭著;将其视为 shell 脚本的 W3Schools。考虑将 bash-hackers.org 或 Wooledge wiki 作为维护准确性的替代方案。 【参考方案1】:

已更改between 3.1 and 3.2。猜猜高级指南需要更新。

这是对新产品的简要描述 自 bash-3.2 以来添加的功能 发布 bash-3.1。一如既往, 手册页(doc/bash.1)是这个地方 寻找完整的描述。

    Bash 中的新功能

剪辑

f。将字符串参数引用到 [[ 命令的 =~ 运算符现在强制 字符串匹配,与其他模式匹配运算符一样。

遗憾的是,除非您有洞察力将模式存储在变量中并直接使用它们而不是正则表达式,否则这会破坏使用脚本的现有引用。下面的例子。

$ bash --version
GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
$ number=2
$ if [[ $number =~ "[0-9]" ]]; then echo match; fi
$ if [[ $number =~ [0-9] ]]; then echo match; fi
match
$ re="[0-9]"
$ if [[ $number =~ $re ]]; then echo MATCH; fi
MATCH

$ bash --version
GNU bash, version 3.00.0(1)-release (i586-suse-linux)
Copyright (C) 2004 Free Software Foundation, Inc.
$ number=2
$ if [[ $number =~ "[0-9]" ]]; then echo match; fi
match
$ if [[ "$number" =~ [0-9] ]]; then echo match; fi
match

【讨论】:

这真的很有趣。引用的正则表达式不再起作用。带空格的不带引号的正则表达式不起作用。基于变量的正则表达式即使包含空格也可以工作。真是一团糟。 有趣的是,这行得通:if [[ $number =~ ["0-9"] ]]; then echo match; fi 这太令人失望了,我们需要依靠echocompat31 解决方法...【参考方案2】:

Bash 3.2 引入了一个兼容性选项 compat31,它将 bash 正则表达式引用行为恢复到 3.1

没有 compat31:

$ shopt -u compat31
$ shopt compat31
compat31        off
$ set -x
$ if [[ "9" =~ "[0-9]" ]]; then echo match; else echo no match; fi
+ [[ 9 =~ \[0-9] ]]
+ echo no match
no match

使用 compat31:

$ shopt -s compat31
+ shopt -s compat31
$ if [[ "9" =~ "[0-9]" ]]; then echo match; else echo no match; fi
+ [[ 9 =~ [0-9] ]]
+ echo match
match

补丁链接: http://ftp.gnu.org/gnu/bash/bash-3.2-patches/bash32-039

【讨论】:

【参考方案3】:

GNU bash,版本 4.2.25(1)-release (x86_64-pc-linux-gnu)

字符串匹配和正则匹配的一些例子

    $ if [[ 234 =~ "[0-9]" ]]; then echo matches;  fi # string match
    $ 

    $ if [[ 234 =~ [0-9] ]]; then echo matches;  fi # regex natch 
    matches


    $ var="[0-9]"

    $ if [[ 234 =~ $var ]]; then echo matches;  fi # regex match
    matches


    $ if [[ 234 =~ "$var" ]]; then echo matches;  fi # string match after substituting $var as [0-9]

    $ if [[ 'rss$var919' =~ "$var" ]]; then echo matches;  fi   # string match after substituting $var as [0-9]

    $ if [[ 'rss$var919' =~ $var ]]; then echo matches;  fi # regex match after substituting $var as [0-9]
    matches


    $ if [[ "rss\$var919" =~ "$var" ]]; then echo matches;  fi # string match won't work

    $ if [[ "rss\\$var919" =~ "$var" ]]; then echo matches;  fi # string match won't work


    $ if [[ "rss'$var'""919" =~ "$var" ]]; then echo matches;  fi # $var is substituted on LHS & RHS and then string match happens 
    matches

    $ if [[ 'rss$var919' =~ "\$var" ]]; then echo matches;  fi # string match !
    matches



    $ if [[ 'rss$var919' =~ "$var" ]]; then echo matches;  fi # string match failed
    $ 

    $ if [[ 'rss$var919' =~ '$var' ]]; then echo matches;  fi # string match
    matches



    $ echo $var
    [0-9]

    $ 

    $ if [[ abc123def =~ "[0-9]" ]]; then echo matches;  fi

    $ if [[ abc123def =~ [0-9] ]]; then echo matches;  fi
    matches

    $ if [[ 'rss$var919' =~ '$var' ]]; then echo matches;  fi # string match due to single quotes on RHS $var matches $var
    matches


    $ if [[ 'rss$var919' =~ $var ]]; then echo matches;  fi # Regex match 
    matches
    $ if [[ 'rss$var' =~ $var ]]; then echo matches;  fi # Above e.g. really is regex match and not string match
    $


    $ if [[ 'rss$var919[0-9]' =~ "$var" ]]; then echo matches;  fi # string match RHS substituted and then matched
    matches

    $ if [[ 'rss$var919' =~ "'$var'" ]]; then echo matches;  fi # trying to string match '$var' fails


    $ if [[ '$var' =~ "'$var'" ]]; then echo matches;  fi # string match still fails as single quotes are omitted on RHS 

    $ if [[ \'$var\' =~ "'$var'" ]]; then echo matches;  fi # this string match works as single quotes are included now on RHS
    matches

【讨论】:

【参考方案4】:

正如其他答案中提到的,将正则表达式放在变量中是实现不同bash 版本兼容的一般方法。您也可以使用此解决方法来实现相同的目的,同时将您的正则表达式保持在条件表达式中:

$ number=1
$ if [[ $number =~ $(echo "[0-9]") ]]; then echo matched; fi
matched
$ 

【讨论】:

以上是关于bash 正则表达式带引号?的主要内容,如果未能解决你的问题,请参考以下文章

使用正则表达式将带引号的字符串与嵌入的非转义引号匹配

使用正则表达式在 C# 中使用转义引号查找带引号的字符串

正则表达式捕获引号内和带/不带空格的数字

正则表达式应该只匹配两种类型的带引号的字符串之一

bash中的正则工具几种引用方式的区别

正则表达式删去双引号vscode