匹配以在bash中全局捕获组

时间:2017-03-18 14:05:30

标签: 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;
}

打印:

got 4 matches:
[values]
[enclosed]
[in some]
[square brackets]

如何实现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[@]}"

但它使用grep和perl-regexes ......

可以用纯粹的bash做到这一点吗?

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:1)

在bash中:

您可以使用少量匹配:

#!/bin/bash
a='some [values] in string [enclosed] [in some] number of [square brackets]'
reg='[^[]*\[([^]]*)\]'
regex="$reg$reg$reg$reg"
[[ $a =~ $regex ]]
printf '%s\n' "${BASH_REMATCH[@]:1}"; echo

reg选择一个

的字符串
  • 没有[[^[]*),
  • 后跟[
  • 后跟几个 ][^]]*),
  • 后跟]

括号内捕获括号内的值。

在正则表达式中重复使用reg可以捕获括号内的几个字符串。这可以扩展到(小)数量的比赛。对于一般解决方案,您需要一个循环,或使用awk。

执行时,上面的脚本将打印:

$ ./script
values
enclosed
in some
square brackets