如何通过命令替换将多个值分配给数组?

如何通过命令替换将多个值分配给数组?

考虑以下 shell 脚本函数:

#!/bin/bash

declare -a dir

function() {
local -a directories=( "A/B/C D" "E/F G H" ) #Initialize local array.
printf "%q " "${directories[@]}"             #"Return" values of array in escaped form.
}

dir=( $(funcion) )

for i in "${dir[@]}"; do
  echo $i
done

我希望命令替换如何工作:

dir=( A/B/C\ D E/F\ G\ H ) #Escape the whitespace.

脚本的结果应该是:

A/B/C D
E/F G H

命令替换的实际工作原理(我认为是因为它的结果):

dir=( A/B/C\\ D E/F\\ G\\ H ) #Escape the backslash.

脚本的结果是:

A/B/C\
D
E/F\
G\
H

有没有办法让它像我一样工作?

答案1

我认为你\nprintf.你有这个:

$ directories=( "A/B/C D" "E/F G H" )
$ printf "%q " "${directories[@]}"

这有效地评估了这一点:

$ printf "%q " "A/B/C D" "E/F G H"
A/B/C\ D E/F\ G\ H

这会导致 for 循环迭代A/B/C\DE/F\G\H

相反,如果您使用"%q\n",您会得到以下结果:

$ printf "%q\n" "${directories[@]}"
A/B/C\ D
E/F\ G\ H

然后,您可以使用以下命令将结果(假设它来自func)读取到数组中:

readarray -t dir < <(func)

答案2

directories=( "A/B/C D" "E/F G H" ) #Initialize local array.
printf "%q " "${directories[@]}"

这将打印引用的值,以便输出适合用作 shell 输入。

dir=( $(func) )

这将获得 的输出func,通过分词和通配运行它,并将结果字段存储在数组中。

这些不是兼容的格式。特别是,后者将其获取的数据视为数据,它不会解析 shell 语法,如引号、转义符或运算符或任何内容。它只查看空白。 (数据中的反斜杠是无法逃避的。它们只是一开始就没有特殊含义。)

如果您想将输入作为 shell 语法进行处理,则需要通过 运行它eval,但这有一个缺点,即其他任何内容也会运行,例如嵌入式命令替换将运行(想想$(reboot))。

更好的方法是一开始就不要将数据转换为 shell 语法。相反,使用一些合适的字符作为终止符打印数组值,并使用readreadarray与进程替换一起读回它们。

例如,使用换行符分隔符:

f() {
    printf "%s\n" "hello world" 'some"quotes\etc'
}
readarray -t arr < <(f)

或者使用 NUL 字符作为分隔符,这样您就可以在值中包含换行符:

g() {
    printf "%s\0" "hello world" 'some"quotes\etc' $'two\nlines\n'
}
readarray -d '' -t arr < <(g)

(顺便说一句,function() ...它在 Bash 中不起作用,因为function那里有一个关键字。不过,它在 Dash 和 Busybox 中起作用,但数组则不起作用。)

相关内容