匹配以在 bash 中全局捕获组

caj*_*ine 3 bash

有这个非常简单的 perl 脚本:

use strict;
use feature 'say';
use warnings;

my $str = q{some [values] in string [enclosed] [in some] number of [square brackets]};
my @matches;
if(my $num =(@matches)= $str =~ / \[ (.*?) \] /gsx ) {
        say "got $num matches:";
        say "[$_]" for @matches;
}
Run Code Online (Sandbox Code Playgroud)

它打印:

got 4 matches:
[values]
[enclosed]
[in some]
[square brackets]
Run Code Online (Sandbox Code Playgroud)

如何实现类似 in 的东西bash

Ps:没有提供任何 bash 代码,因为我什至不知道如何开始。该${BASH_REMATCH[@]}不会在一线工作的全局......对于使用BASH_REMATCH需要提前知道cature组的数量。所以,不知道...... :( 我能做到的最接近的是:

str='some [values] in string [enclosed] [in some] number of [square brackets]'
echo "$str"
mapfile -t arr < <(grep -oP '\[\K(.*?)(?=])' <<< "$str")
echo "got ${#arr[@]} matches"
printf "[%s]\n" "${arr[@]}"
Run Code Online (Sandbox Code Playgroud)

但它使用带有 perl 正则表达式的 grep ......

可以在纯 bash 中做到这一点吗?

che*_*ner 5

bash正则表达式匹配不提供这种支持。您需要通过迭代不断缩小的输入字符串来模拟它。

str='some [values] in string [enclosed] [in some] number of [square brackets]'

# Match a string consisting of anything *except* ]
# between literal [ and ]
regex='\[[^]]+\]'
while [[ $str =~ $regex ]]; do
    m=${BASH_REMATCH[0]}
    echo "$m"
    str=${str##*"$m"}  # Remove the longest prefix ending with the match
done
Run Code Online (Sandbox Code Playgroud)

从技术上讲,您不需要捕获组,只需要一个与您要捕获的字符串完全匹配的正则表达式,因为=~它将与第一个匹配。

  • 不错的把戏。只需要删除 **shortest** 前缀 `${str#*"$m"}` 因为例如对于字符串 `x [a] x [b] x [a] x [a] x [c]`它将只打印 `ac` 而不是 `abaac`。 (2认同)