Bash:将数组中的每个项目转换为带有标志的命令参数

时间:2019-01-17 22:45:51

标签: bash

假设我们有数组FOO=("hello world" "xyzzy")。我们要运行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[@]}"

有没有一种方法不需要显式循环和数组副本?

1 个答案:

答案 0 :(得分:2)

创建bash≥4.4的新阵列

您可以使用空字节定界符(\0)打印数组,在每个条目前面插入-Z\0,然后再次将结果读取为数组:

由于bash,以下解决方案要求mapfile -d≥4.4。另外,请参阅此答案末尾的hack。

processargs() {
   (( "$#" )) && printf -- '-Z\0%s\0' "$@"
}
array=('' 1 ' x y ' $'multiline\ntext')
mapfile -d '' arrayWithZ < <(processargs "${array[@]}")

为了进行测试,我们使用内置的declare -p打印结果数组arrayWithZ的所有条目(手动插入换行符以提高可读性)。

$ declare -p arrayWithZ
declare -a arrayWithZ=(
  [0]="-Z"
  [1]=""
  [2]="-Z"
  [3]="1"
  [4]="-Z"
  [5]=" x y "
  [6]="-Z"
  [7]=$'multiline\ntext'
)

对于空数组,我们不插入任何-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[@]}")"