linux 如何在Bash中用可以包含多行的字符串填充数组?[重复]

kd3sttzy  于 2023-03-22  发布在  Linux
关注(0)|答案(1)|浏览(123)

此问题在此处已有答案

Convert a string into an array with bash, honoring quotes for grouping [duplicate](3个答案)
Bash doesn't parse quotes when converting a string to arguments(5个答案)
19小时前关门了。
我有一个带有多个字符串的变量,它可以包含多行:

var="foo 'bar baz' 'lorem
ipsum'"

我需要它们都作为数组元素,所以我的想法是使用xargs -n1将每个带引号或不带引号的字符串读入单独的数组元素:

mapfile -t arr < <(xargs -n1 <<< "$(echo "$var")" )

但这会导致这个错误:

xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option

最后,我唯一的想法是用回车替换换行,然后恢复它:

# fill array                                  preserve line feed (dirty)
mapfile -t arr < <(xargs -n1 <<< "$(echo "$var" | tr '\n' '\r')" )

# restore line feed
for (( i=0; i<${#arr[@]}; i++ )); do
  arr[i]=$(echo "${arr[$i]}" | tr '\r' '\n')
done

它的工作原理是:

# for (( i=0; i<${#arr[@]}; i++ )); do echo "index: $i, value: ${arr[$i]}"; done
index: 0, value: foo
index: 1, value: bar baz
index: 2, value: lorem
ipsum

但是只要输入变量不包含回车符。
我假设我需要xargs输出每个由空字节分隔的结果,并使用mapfile-d ''导入,但似乎xargs缺少print0选项(tr '\n' '\0'将操作多行字符串本身)。

km0tfn4u

km0tfn4u1#

这段Shellcheck-clean代码演示了一种方法,通过使用Bash正则表达式从字符串中提取部分:

#! /bin/bash -p

var="foo 'bar baz' 'lorem
ipsum'"

leadspace_rx='^[[:space:]]+(.*)$'
bare_rx="^([^'[:space:]]+)(.*)\$"
quoted_rx="^'([^']*)'(.*)\$"

arr=()
while [[ -n $var ]]; do
    if [[ $var =~ $leadspace_rx ]]; then
        var=${BASH_REMATCH[1]}
    elif [[ $var =~ $bare_rx ]]; then
        arr+=( "${BASH_REMATCH[1]}" )
        var=${BASH_REMATCH[2]}
    elif [[ $var =~ $quoted_rx ]]; then
        arr+=( "${BASH_REMATCH[1]}" )
        var=${BASH_REMATCH[2]}
    else
        printf 'ERROR: Cannot handle: %s\n' "$var" >&2
        exit 1
    fi
done

declare -p arr
  • 输出为declare -a arr=([0]="foo" [1]="bar baz" [2]=$'lorem\nipsum')
  • 如果您认为拆分字符串的想法值得追求,那么可以很容易地将其封装在一个函数中。
  • 当前的代码做了一些你可能没有预料到的事情。例如,字符串a'b'c被转换为数组(a b c)。如果你能提供一个更精确的输入字符串格式的规范,我会看看是否可以修改代码来处理它。

相关问题