bash - extglob 第二个“零个或多个”运算符不起作用

bash - extglob 第二个“零个或多个”运算符不起作用

鉴于:

$ shopt -s extglob
$ TEST="    z abcdefg";echo ">>${TEST#*( )z*( )}<<"
>> abcdefg<<

为什么字母“a”前面有一个空格?我希望第二个*( )能够匹配空间,但它并不适合这样做。

我期望相当于:

$ echo ">>$(echo -n "${TEST}" | perl -pe "s/^ *z *//g")<<"
>>abcdefg<<

*( )如果我指定下一个以下字符(即“a”),则第二个匹配:

$ shopt -s extglob
$ TEST="    z abcdefg";echo ">>${TEST#*( )z*( )a}<<"
>>bcdefg<<

重击版本: GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

答案1

${TEST#...}匹配最短的字符串,即 z 后面跟着零个空格。您需要${TEST##...}最长的匹配。

答案2

这是由于非贪婪子字符串删除和您正在使用的模式类型之间的相互作用造成的。

来自bash手册,

?(pattern-list)

匹配零次或一次出现的给定模式。

*(pattern-list)

匹配零次或多次出现的给定模式。

+(pattern-list)

匹配给定模式的一次或多次出现。

来自我最喜欢的 bash 解释字符串操作,

${string#substring}

删除$substring前面的最短匹配项$string

${string##substring}

删除$substring前面最长的匹配项$string

因此,当您指定 时${TEST#*( )z*( )},您是在说:“请删除具有零个或多个空格的最短子字符串 a z,然后删除零个或多个空格。

最后一个空格的匹配比没有它的匹配要长,因此最后一个空格永远不会被匹配。

要纠正此问题,您可以使用${TEST##*( )z*( )}匹配以零个或多个空格结尾的最长前缀,或${TEST#*( )z+( )}匹配以一个或多个空格结尾的最短前缀(这在功能上等同于匹配以一个空格结尾的最短前缀)。

答案3

当您想要模仿 is (perl) 正则表达式时,请使用 a regexnot a pattern

$ test="    z abcdefg"
$ regex='^ *z *(.*)'
$ [[ $test =~ $regex ]]
$ echo ">>${BASH_REMATCH[1]}<<"
>>abcdefg<<

正则表达式是扩展的正则表达式,而不是完整的 PCRE。

相关内容