条件表达式中 grep -E 正则表达式和 Bash 正则表达式之间的区别



对于应用于同一字符串的相同正则表达式,为什么grep -E匹配,而[[ ]]中的 Bash=~运算符不匹配?

$ D=Dw4EWRwer
$ echo $D|grep -qE '^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_- ]{1,22}$' || echo wrong pattern
$ [[ "${D}" =~ ^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_- ]{1,22}$ ]] || echo wrong pattern
wrong pattern

更新:我确认这有效:

[[ "${D}" =~ ^[A-Z][A-Za-z0-9]{1,2}[[:alnum:] _-]{1,22}$ ]] || echo wrong pattern

问题(对于两个版本的代码)出在此字符类上:

[[:alnum:]_- ]

grep版本中,由于regex括在单引号中,因此反斜杠不会转义任何内容,并且grep收到的字符范围正是上面表示的方式。

bash版本中,反斜杠()转义了它后面的空格,[[ ]]用于测试的实际字符类是[[:alnum:]_- ]

因为在ASCII表中,下划线(_)在空格()和反斜杠(bash)之后,这两个字符类都不正确。

对于regex版本,您可以使用:

[[ "${D}" =~ ^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_- ]{1,22}$ ]]; echo $?

以验证其结果。如果2不正确,则退出代码为-


如果你想在字符类中放一个破折号([),你必须把它作为类中的第一个字符(紧随[^之后,或者right before the closing如果它是一个否定类)或作为类中的最后一个字符(grep]')。

代码的bash版本应该是(无需在用单引号括起来的字符串内转义任何内容):

$ echo $D | grep -qE '^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_ -]{1,22}$' || echo wrong pattern

代码的版本应为:

[[ "${D}" =~ ^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_ -]{1,22}$ ]] || echo wrong pattern

根据您的注释,您希望括号表达式包含字母数字字符、空格、下划线和短划线,因此破折号不应表示范围。若要向括号表达式添加连字符,它必须是其中的第一个或最后一个字符。此外,您不必在括号表达式中转义内容,因此可以删除反斜杠。您的 grep 正则表达式在括号表达式中包含文字[[ ]]

$ grep -q '[]' <<< '' && echo "Match"
Match

在 Bash 正则表达式中,必须对空格进行转义,因为字符串首先由 shell 读取,但请参阅下面的如何避免这种情况。

首先,修复您的正则表达式:

^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_ -]{1,22}$

反斜杠消失,连字符移动到末尾。将其与 grep 一起使用可以正常工作:

$ D=Dw4EWRwer
$ grep -E '^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_ -]{1,22}$' <<< "$D"
Dw4EWRwer

要直接在[A-Z]中使用正则表达式,必须对空格进行转义:

$ [[ $D =~ ^[A-Z][A-Za-z0-9]{1,2}[[:alnum:]_ -]{1,22}$ ]] && echo "Match"
Match

我会进行以下更改:

  • 尽可能使用字符类:[[:upper:]][A-Za-z0-9][[:alnum:]][[ ]]
  • 将正则表达式存储在变量中以便在CC_29中使用;这有两个优点:没有 shell 特有的转义字符,以及与旧 Bash 版本的兼容性,因为引用要求在 3.1 和 3.2 之间发生了变化(参见 BashGuide 中的模式文章)。

然后,对于 grep,正则表达式将变成这样:

$ grep -E '^[[:upper:]][[:alnum:]][[:alnum:]_ -]{1,22}$' <<< "$D"
Dw4EWRwer

在 Bash 中:

$ re='^[[:upper:]][[:alnum:]][[:alnum:]_ -]{1,22}$'
$ [[ $D =~ $re ]] && echo "Match"
Match

最新更新