对于应用于同一字符串的相同正则表达式,为什么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