shell 如何使用2D数组作为bash脚本中函数的结果

lztngnrs  于 2022-12-30  发布在  Shell
关注(0)|答案(1)|浏览(121)

我有以下功能:

function regex_match_2d_list {
  local regex=$1
  local text=$2
  local groups=()
  while [[ $text =~ $regex ]]; do
    local group=()
    for (( i=0; i<${#BASH_REMATCH[@]}; i++ )); do
      group+=("${BASH_REMATCH[$i]}")
    done
    groups+=("${group[@]}")
    text=${text#*"${BASH_REMATCH[0]}"}
  done
  echo "${groups[@]}"
}

我尝试做的是有一个函数,它将接收一个正则表达式和一个文本,并输出一个二维列表,列表中的每个元素都由正则表达式中的所有组组成:

pattern="^([a-z]+)\s([a-z]+)"
text="hello world
foo bar"

res=$(regex_match_2d_list "$pattern" "$text")
echo "${res[0,1]}"

如果我没有理解错的话,通过res[0,2],我应该得到“world”,因为它是第一个元素的第二组。

相反,如果我什么也没得到,有没有人能给我解释一下我在这里做错了什么?

xe55xuns

xe55xuns1#

注意:您可以通过在匹配后立即添加'declare -p BASH_REMATCH text'来自己调试这些问题。
行:text=${text#*"${BASH_REMATCH[0]}"}应删除匹配项。但是,匹配项不包括第二个标记后的尾随分隔符(“hello world”和“foo bar”之间的新行)。您希望更改匹配项以删除任何尾随新行。
一个可能的解决方案-在模式的末尾添加新行。为了处理最后一行没有以新行结束-我将其设置为可选的(使用'?')。可以将新行附加到文本中作为替代。

pattern="^([a-z]+)\s([a-z]+)"$'\n?'

第二个问题是将BASH_REMATCH传输到组(通过中间组变量)。当前代码还复制RE_BATCH的元素0,这将导致组中的条目重复。请考虑改用groups+=(${BASH_REMATCH[@]}
最后一个问题是对“res”的赋值。当前代码将数组“扁平化”为单个字符串。您可能希望将res作为数组获取。一种可能(但不总是安全的)是使用数组赋值res=($(regex_match...))。
最终代码:

function regex_2 {
  local regex=$1
  local text=$2
  local groups=()
  while [[ $text =~ $regex ]]; do
    groups+=("${BASH_REMATCH[@]:1}")
    text=${text#*"${BASH_REMATCH[0]}"}
  done
  echo "${groups[@]}"
}

pattern="^([a-z]+)\s([a-z]+)"$'\n?'
text="hello world
foo bar"

res=($(regex_2 "$pattern" "$text"))
declare -p res

相关问题