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?
}

次の値の calls を使用:

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、配列を持つ他のほとんどの健全なシェルと同じように使用することをお勧めします。関数と配列を含む他のすべてのソリューションでは、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 に答える