分配" $ @"到Bash中的变量并保留转义

时间:2015-08-28 17:41:25

标签: bash escaping arguments printf

如果我将以下脚本保存为' 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

在某种程度上,这些都是不正确的。如何将"$@"分配给变量,并使其与第一个命令回显相同的输出?

1 个答案:

答案 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编码)。