shell 为什么echo返回的内容与没有返回的内容不同

4xy9mtcn  于 2022-12-30  发布在  Shell
关注(0)|答案(3)|浏览(217)

我有以下案例:
正则表达式:$'\[OK\][[:space:]]+([[:alnum:]_]+)\.([[:alnum:]_]+)([^[]*)'
正文:

[OK] AAA.BBBBBB
aaabbbcccdddfffed
asdadadadadadsada
[OK] CCC.KKKKKKK
some text here
[OK] OKO.II

如果我使用这个网站https://regex101.com/r/qw4B5O/1将看起来像这样:

现在...如果我有下面的代码:

var_test=()
while [[ $text =~ $regex ]]; do
  var_test+=("${BASH_REMATCH[@]:1}")
  text=${text#*"${BASH_REMATCH[0]}"}
done
declare -p var_test

我将得到正确的输出:

declare -a var_test=([0]="AAA" [1]="BBBBBB" [2]=$'\naaabbbcccdddfffed\nasdadadadadadsada\n' [3]="CCC" [4]="KKKKKKK" [5]=$'\nsome text here\n' [6]="OKO" [7]="II" [8]="")

但是一旦我将它转换成这样一个函数:

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

res=($(split_by_regex "$regex" "$text"))
declare -p res

我将得到错误的输出:

declare -a res=([0]="AAA" [1]="BBBBBB" [2]="aaabbbcccdddfffed" [3]="asdadadadadadsada" [4]="CCC" [5]="KKKKKKK" [6]="some" [7]="text" [8]="here" [9]="OKO" [10]="II")

经过一些调试后,错误看起来像是来自echo "${groups[@]}",因为如果我在函数中检查groups,它看起来应该是这样,但在我从函数中获得结果后,它不是。
抱歉,如果这是一个显而易见的问题,但我是新的bash和shell脚本,我正在努力弄清楚。

fcg9iug3

fcg9iug31#

从函数中返回数组是很棘手的,因为正如您所注意到的,空格将被用于拆分数组中的值,因此不会被保留。
我建议使用nameref代替。

function split_by_regex {
  local -n groups=$1   # -n makes `groups` a reference to `res`
  local regex=$2
  local text=$3
  while [[ $text =~ $regex ]]; do
    groups+=("${BASH_REMATCH[@]:1}")
    text=${text#*"${BASH_REMATCH[0]}"}
  done
}

declare -a res                       # declare `res` as an array
split_by_regex res "$regex" "$text"  # pass in `res` as a parameter
declare -p res                       # prints the expected result
uyhoqukh

uyhoqukh2#

由于性能原因,传输数组(使用nameref或global)是最有效的方法。如果这不起作用,可以使用readarray将子命令的(标准)输出解析为array。
对于输出不包含新行的简单情况,可以使用“printf”将数组转换为新行分隔的输出

function foo {
    out=(foo "bar baz" 123 "A B C")
    printf "%s\n" "${out[@]}"
}

readarray res <<< "$(foo)"

对于一般情况,当输出可能包含新行时,可以使用NUL作为分隔符(类似于许多GNU实用程序支持的-print 0或-0),然后用NUL作为分隔符解析输出。如果NUL不起作用,可以使用\1
此外,无法使用单行文档(<<<)。在使用带有自定义分隔符的<<<时,似乎是bash中的一个错误-它在文本中添加了一个新行,导致额外的注解。

function foo {
    out=(foo "bar baz" 123 $'a\nb' "A B C")
    printf "%s\0" "${out[@]}"
}

readarray -d $'\0' -t res < <(foo)
huus2vyu

huus2vyu3#

另一种方法是在函数外部声明数组,如果工作流/要求允许的话,如下所示:

regex=$'\[OK\][[:space:]]+([[:alnum:]_]+)\.([[:alnum:]_]+)([^[]*)'

text='[OK] AAA.BBBBBB
aaabbbcccdddfffed
asdadadadadadsada
[OK] CCC.KKKKKKK
some text here
[OK] OKO.II'

#: `declare -a groups` will work as well
#: Declare it outside of the function
groups=()

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

split_by_regex "$regex" "$text"

#: Now one can access/process the array `groups` outside of the function.
declare -p groups
  • 如果没有nameref,上面的代码是一种替代方法。

相关问题