间接而不使用eval

时间:2012-11-24 13:02:04

标签: arrays bash indirection

我正在寻找一种干净的方式(没有eval命令)来对数组进行间接引用。以下是对我想要的更准确的描述:

function valueof {
   echo "indirection1 \$$1=${!1}"
   eval "echo indirection2 \\\$$1=\${$1[@]}" # Untill this step its fine.

   # My final objective is to do this (but eval is not a very sexy solution) : 
   for i in $(eval "echo \${$1[@]}") ; do 
      echo $i
   done

   # Here is the "problem", ie. "bad substitution"
   echo "indirection3 \$$1=${!1[@]}"  
   # "1[@]" is evaluated first i guess?
}

使用以下值调用:

a=("a" "aa" "aaa")
b=("b" "bb" "bbb")
valueof a
valueof b

我的输出是:

indirection1 $a=a
indirection2 $a=a aa aaa
a
aa
aaa
indirection1 $b=b
indirection2 $b=b bb bbb
b
bb
bbb

在stderr上:

prog.sh: line 10: indirection3 $1=${!1[@]}: bad substitution
prog.sh: line 10: indirection3 $1=${!1[@]}: bad substitution

感谢您对此问题的回答/评论:)

1 个答案:

答案 0 :(得分:1)

我建议从git devel分支构建Bash并像使用数组一样使用typeset -n和大多数其他理智的shell一样。涉及函数和数组的所有其他解决方案都需要eval或利用奇怪的无证行为。两者都要求平等关怀,而且一方面不一定有优势。

这是一个一般性的例子,它展示了你可以在没有eval的情况下间接做的所有事情。命令空间冲突仍然存在。

isSubset() {
    local -a 'xkeys=("${!'"$1"'[@]}")' 'ykeys=("${!'"$2"'[@]}")'
    set -- "${@/%/[key]}"

    (( ${#xkeys[@]} <= ${#ykeys[@]} )) || return 1

    local key
    for key in "${xkeys[@]}"; do
        [[ ${!2+_} && ${!1} == "${!2}" ]] || return 1
    done
}

a=(abc def [4]=ghi jkl)
b=(abc def [4]=ghi jkl)
c=(abc [3]=def [6]=ghi xyz)
isSubset a b
echo $? # 0
isSubset b c
echo $? # 1

在某些方面,这是伪装eval。大多数人都不知道他们在将变量名称传递给内置函数和算术表达式时有效地执行eval。您必须始终确保变量名称和索引在内部受到控制,并且不会受到用户输入或其他无法保证结果的副作用的影响。

根据您对词语分词和引用的误用来判断,您应该切换到另一种语言。 Bash并不是真正意图处理安全封装。