考虑以下 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
我认为你\n
的printf
.你有这个:
$ 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\
、D
、E/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 语法。相反,使用一些合适的字符作为终止符打印数组值,并使用read
或readarray
与进程替换一起读回它们。
例如,使用换行符分隔符:
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 中起作用,但数组则不起作用。)