如果我将以下脚本保存为' args.bash'并运行bash args.bash -a 'foo bar'
#!/bin/bash
main() {
set -x
which "$@"
local args="$@"
which "$args"
which $args
local args=$(printf " %q" "$@")
which "$args"
which $args
}
main "$@"
我惊讶地发现这些打印出不同的结果。第一个打印:
which -a 'foo bar'
我期待的!它正确地对参数进行分组。
其余的按顺序打印:
which '-a foo bar'
which -a foo bar
which ' -a foo\ bar'
which -a 'foo\' bar
在某种程度上,这些都是不正确的。如何将"$@"
分配给变量,并使其与第一个命令回显相同的输出?
答案 0 :(得分:4)
使用数组变量,而不是标量:
items=( "$@" )
which -a "${items[@]}"
但是,如果您必须使用标量 [1] ,那么您使用printf '%q '
的方法是正确的。但请注意,printf %q
创建了一个字符串,当通过完整的解析器时,它将评估回自身(因此需要eval
或等效字符串,以确保完整的解析器是调用的):
printf -v items_str '%q ' "$@"
eval "which -a $items_str"
[1] 其中一个具有bash扩展名(例如printf -v
和%q
但不能使用数组的情况数量有限,但它们确实存在;特别是,我想到了通过环境将值传递给子流程。但是,在数组不合适的大多数情况下,我希望使用一系列不同的环境变量(每个值一个),或者传递一个NUL分隔的流(由printf '%s\n' "$@"
创建)更多适当的,即使(对于环境)它可能需要被转义(例如,通过base64编码)。