【问题标题】:Assigning "$@" to a variable in Bash and preserving escaping将“$@”分配给 Bash 中的变量并保留转义
【发布时间】:2015-08-28 17:41:25
【问题描述】:

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

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

【问题讨论】:

  • 您不能在字符串中存储任意命令/参数并保持正确的引用/等。有关此问题的讨论,请参阅 Bash FAQ 050。你需要使用一个数组。
  • 嗯——他正在使用printf %q,这有点改变,但数组仍然是正确的。
  • printf %q 是我唯一知道要尝试的东西 - 愿意接受任何其他建议。
  • $@ 具有特殊的行为,正是因为普通参数不能在单个字符串中保持不同的参数(并且数组不在 POSIX 中,而 $@ 是) .

标签: bash escaping arguments printf


【解决方案1】:

使用数组变量,而不是标量:

items=( "$@" )
which -a "${items[@]}"

但是,如果您必须使用标量[1],那么printf '%q ' 的方法是正确的;但是请注意,printf %q 创建了一个字符串,当通过完整解析器运行时,该字符串将返回到自身(因此需要eval 或等效项来确保调用完整的解析器):

printf -v items_str '%q ' "$@"
eval "which -a $items_str"

[1] 具有printf -v 和%q 等bash 扩展名但不能使用数组的情况数量有限,但确实存在;特别是,我想到了通过环境将值传递给子流程。但是,在数组不合适的大部分情况下,我希望使用一系列不同的环境变量(每个值一个),或者传递一个 NUL 分隔的流(由printf '%s\n' "$@" 创建)更合适,即使(就环境而言)它可能需要转义(例如,通过 base64 编码)。

【讨论】:

  • 呃,所以你必须在那里使用评估?
  • 如果你不想做正确的事情并使用数组,是的。
  • (请仔细阅读常见问题解答 50,在问题的 cmets 中链接,以了解 为什么这是必要的)。
  • 请记住%q 和-v 都是bash 对printf 的扩展,因此您不妨使用数组。
  • @chepner,确实;无法使用数组的情况是我们实际上是通过环境导出此列表。 (在其他情况下,例如通过串行线路,NUL 分隔的形式会更好)。即使通过环境发送它,我自己也可能会使用不同的方法(base64 编码 NUL 分隔的流?多个单独的环境变量?)如果组件或通信协议有任何可能不受信任的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-11
  • 2015-04-11
  • 2015-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多