我有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进行攻击。
答案 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中的反斜杠等等。