2

我正在寻找一种干净的方式(没有 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

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

4

1 回答 1

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 并不是真的要处理安全封装。

于 2012-11-24T16:13:15.877 回答