如何让复杂的正则表达式在 bash 中工作

如何让复杂的正则表达式在 bash 中工作

这个想法是对 url 的输入模式进行基本检查:

$ ns='abc.def.com'
$ reg_expr="\N*\.(\D{2}|\D{3})$"
$ echo $reg_expr
\N*\.(\D{2}|\D{3})$
$ [[ $ns =~ "$reg_expr" ]] && echo "ok" || echo "no"
no

但是,正则表达式总是失败。在线正则表达式检查相同模式工作正常。

https://regex101.com/r/vXxv1w/1

为什么会出现这种情况?

答案1

\N*\.(\D{2}|\D{3})$

是一个 Perl 正则表达式。 bash 的[[ =~ ]]运算符采用 POSIX 扩展正则表达式,而不是 Perl 正则表达式。

要使用 perl 风格的正则表达式,请使用 zsh 及其rematchpcre选项:

set -o rematchpcre
[[ $ns =~ '\N*\.(\D{2}|\D{3})$' ]]

现在,该正则表达式没有多大意义。

  • \N旨在匹配除换行符之外的任何字符,但除非您设置标志s(例如使用(?s)),.否则无论如何都不会匹配换行符,因此您可以替换\N.
  • 位于<anything>*正则表达式的开头或结尾是没有意义的,因为它匹配0或更多<anything>,所以它也不匹配任何东西。[[ $ns =~ '\.(\D{2}|\D{3})$' ]]功能上是等价的。
  • \D匹配除十进制数字之外的任何字符,即 0123456789 或类似 0123456789٠١٢٣٤٥٦٧٨٩0123356789ot德的任何字符。 ८९০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯୦୧୨୩୪୫୬୭୭ ୯௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮ ൯෦෧෨෩෪෫෬෭෮෯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨ ༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩᠐᠑᠒᠓᠔ ᠕᠖᠗᠘᠙᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕ ᪖᪗᪘᪙᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕ ᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꧐꧑꧒꧓꧔꧕ ꧖꧗꧘꧙꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹0123456789

答案2

在 的手册页中bash,有几个段落描述了[[ expression ]]测试中有效的运算符。正则表达式匹配的一篇说:

还可以使用附加二元运算符 =~,其优先级与 == 和 != 相同。使用时,运算符右侧的字符串被视为 POSIX 扩展正则表达式并进行相应的匹配...

(略过几句话)

如果模式的任何部分被引用,则引用的部分将按字面匹配。这意味着引用部分中的每个字符都与其自身匹配,而不具有任何特殊的模式匹配含义。如果模式存储在 shell 变量中,则引用变量扩展会强制整个模式按字面匹配。

总而言之,在 内部[[ expression ]],不要在正则表达式两边加上引号,也不要在包含正则表达式的变量两边加上引号。即使您已指定=~为比较运算符,引用正则表达式也会将比较更改为纯粹的字符串匹配,例如==.

最好按照手册页中的参考资料查看支持哪些正则表达式语法。您可能需要使用[[:digit:]]and[^[:digit:]]而不是\dand \D。 (我可能会弄错,所以你自己检查一下)

相关内容