将“$ @”存储到变量中以供稍后使用,尊重引用的args

时间:2014-02-26 11:08:21

标签: bash

我有project written in bash。接口的一部分要求用户使用一层间接调用bash函数,如下所示:

require some_fun "arg 1" "arg 2"

执行some_fun "arg 1" "arg 2"(然后做一些额外的事情,因此它存在的原因)。目前我只是调用"$@"来执行此操作,一切正常。

我现在需要推迟这些函数调用,直到稍后才能找到在Bash中执行此操作的方法。实际上,我希望每次调用"$@"时将require推送到堆栈,然后循环遍历该堆栈并执行参数,就像我当前的行为一样。这将需要多维数组,bash不支持,所以我正在尝试这个:

require() {
  dep_num=${#SK_deps[@]}
  dep_var="SK_dep_$dep_num"
  eval $dep_var="$@"
  SK_deps+=($dep_var)
}

这基本上生成一个变量来存储“$ @”并将变量名称放在$SK_deps中。

然后我尝试使用:

迭代列表
for dep_var in ${SK_deps[@]}
do
  ${!dep_name}
done

但这似乎打破了引用的论点,所以:

require some_fun "arg 1" "arg 2"

被解释为:

require some_fun arg 1 arg 2

没有引号。

有什么办法可以做我想做的事吗?使用“$ *”也会导致报价定位丢失。感觉应该有一种方法可以在Bash中执行此操作,而不会使用sed / awk进行攻击。

3 个答案:

答案 0 :(得分:5)

eval解决方案并不是那么糟糕。关键是利用printf shell-quoted 机制,它将为您处理所有棘手的案例:

require() {
    local quoted
    printf -v quoted ' %q' "$@"
    SK_deps+=("$quoted")
}

然后你可以正常运行它:

for dep in "${SK_deps[@]}"; do eval $dep; done

答案 1 :(得分:1)

扩展时引用数组:

for dep_var in "${SK_deps[@]}"
do
  ${!dep_name}
done

以下一行似乎也很可疑:

eval $dep_var="$@"

尝试使用set -xv运行脚本,以了解变量的实际扩展方式。

答案 2 :(得分:0)

我发现了一个使用eval的非常难看的解决方案,因此我们将非常感谢任何更好的建议。

require() {
  local tmp_var=""
  for arg in "$@"
  do
    tmp_var="$tmp_var \"$arg\""
  done
  SK_deps+=("$tmp_var")
}

然后:

for dep in "${SK_deps[@]}"
do
  eval $dep
done

很明显使用eval就像这样充满了边缘情况,例如args中的引号或args中的反斜杠等等。