Bash:将数组中的每个项转换为带有标志的命令参数
假设我们有一个数组Bash:将数组中的每个项转换为带有标志的命令参数,bash,Bash,假设我们有一个数组FOO=(“hello world”“xyzy”)。我们希望运行thing工具,将$FOO的每个元素作为单独的-Z标志传递,从而生成以下命令: thing -Z "hello world" -Z "xyzzy" 这些方法不起作用: # Equivalent to `thing "-Z hello world" "-Z xyzzy"` thing "${FOO[@]/#/-Z }" # Equivalent to `thing "-Z hello world -Z xyzzy
FOO=(“hello world”“xyzy”)
。我们希望运行thing
工具,将$FOO
的每个元素作为单独的-Z
标志传递,从而生成以下命令:
thing -Z "hello world" -Z "xyzzy"
这些方法不起作用:
# Equivalent to `thing "-Z hello world" "-Z xyzzy"`
thing "${FOO[@]/#/-Z }"
# Equivalent to `thing "-Z hello world -Z xyzzy"`
thing "${FOO[*]/#/-Z }"
# Equivalent to `thing -Z hello world -Z xyzzy`
thing ${FOO[@]/#/-Z }
# Equivalent to `thing -Z hello world -Z xyzzy`
thing ${FOO[*]/#/-Z }
我可以做的是在数组的每个元素之间插入一个-Z
:
FOO2=()
for x in "${FOO[@]}"; do FOO2+=("-Z" "$x"); done
thing "${FOO2[@]}"
有没有一种不需要显式循环和数组副本的方法?使用bash
≥ 4.4
您可以使用空字节分隔符(\0
)打印数组,在每个条目前面插入-Z\0
,然后再次将结果作为数组读取:
以下解决方案需要bash
≥ 4.4由于映射文件-d
。另一种选择,请参见本答案末尾的hack
processargs() {
(( "$#" )) && printf -- '-Z\0%s\0' "$@"
}
array=('' 1 ' x y ' $'multiline\ntext')
mapfile -d '' arrayWithZ < <(processargs "${array[@]}")
对于空数组,我们不插入任何-Z
。如果array=()
那么arrayWithZ=()
使用eval
,尤其是对于bash
<4.4
如果不需要显式数组arrayWithZ
,那么可以使用以下方法。即使在这种情况下,eval
应该是安全的,我还是建议不要使用它——也许我确实监督了一些事情。但是,当您被困在bash
<4.4中时,这种攻击可能很有用,因为不再需要mapfile-d
processargs() {
(( "$#" )) && printf -- '-Z %q ' "$@"
}
array=('' 1 ' x y ' $'multiline\ntext')
eval "yourCommand $(processargs "${array[@]}")"
虽然没有做出明确的声明,但我会注意到显式循环就是我所做的。如果工具允许参数直接附加到
-Z
(即thing“-Zhello world”“-Zxyzzy”
),那么您可以使用thing“${FOO[@]/#/-Z}”
。否则,我认为您需要使用循环。我喜欢@GordonDavidson的建议,因为许多GNU风格的工具将通过它们的长选项来支持这一点,例如sed-efoo-ebar
=>sed--expression=foo--expression=bar
您可以使用printf--'-Z\0%s\0'$@
来避免通过sed
,但这实际上只是一种更复杂的方法,可以创建一个插入了额外参数的数组副本。@thatotherguy很好!这不仅更短,而且可以在BSD上运行。我根据你的建议编辑了我的答案。
processargs() {
(( "$#" )) && printf -- '-Z %q ' "$@"
}
array=('' 1 ' x y ' $'multiline\ntext')
eval "yourCommand $(processargs "${array[@]}")"