我知道我可以做类似的事情:
[[ $s =~ ^(re)(re)$ ]]
用一系列括号表达式匹配填充BASH_REMATCH
数组。但是可以匹配这些匹配中的未知数吗?例如,我得到以下信息:
s='abc defghi jklm nop '
[[ $s =~ ^([^ ]+ +)+$ ]]
declare -p BASH_REMATCH
输出:
declare -ar BASH_REMATCH=([0]="abc defghi jklm nop " [1]="nop ")
我认为每次匹配时都将括号表达式重写到BASH_REMATCH[1]
上。
我真正想看到的是:
declare -ar BASH_REMATCH=([0]="abc defghi jklm nop "
[1]="abc "
[2]="defghi "
[3]="jklm "
[4]="nop ")
在单个命令中有可能吗?
答案 0 :(得分:4)
很好,但是我认为您要的是未知数量的子表达式。
如下所示的循环可能是最好的选择:
s='abc defghi jklm nop '
a=()
t="$s"
while [[ $t =~ ^([^ ]+ +) ]]; do
a+=( "${BASH_REMATCH[1]}" )
t="${t#${BASH_REMATCH[1]}}"
done
declare -p a=()
输出:
declare -a a=([0]="abc " [1]="defghi " [2]="jklm " [3]="nop ")
在不损害原始字符串的情况下,这将从字符串开头剥离模式,然后将模式添加到结果数组,并使用“模式扩展”从字符串副本的开头剥离匹配项。当然,如果您希望它更美观,可以将其放在函数中;请记住,不能从函数返回数组,您需要使用全局数组或引用:
function ssplit() {
local -n a="$1"
local t="$2"
while [[ $t =~ ^([^ ]+ +) ]]; do
a+=( "${BASH_REMATCH[1]}" )
t="${t#${BASH_REMATCH[1]}}"
done
}
declare -a foo=()
ssplit foo "$s"
declare -p foo
输出:
declare -a foo=([0]="abc " [1]="defghi " [2]="jklm " [3]="nop ")
请注意,local -n
是bash版本4引入的功能。
另一种可能是基于对字符串的分析来构建匹配正则表达式:
x=( $s )
printf -v pat '%s' $(printf '%.0s([^[:space:]]+[[:space:]]+)' $(seq 1 "${#x[@]}"))
[[ $s =~ $pat ]] && declare -p BASH_REMATCH
输出:
declare -ar BASH_REMATCH=([0]="abc defghi jklm nop " [1]="abc " [2]="defghi " [3]="jklm " [4]="nop ")
我不太喜欢编写代码的代码,但这似乎行得通。尽管它不是单个命令,但至少可以避免while循环。请注意,在幕后,bash仍在遍历printf
的参数以构建$pat
。