0

これが私の問題の最も単純な蒸留バージョンです。ここで自明ではないにしても、残っている複雑さには正当な理由があります。さらに、スクリプトは内部的なものであり、悪意のあるコードを実行する可能性がないため、eval はまったく問題ありません。それがどれほど邪悪であるかについて聞く必要はありません... ;) とりあえず、キー文字列のパイプとコロンが必須の区切り文字であると仮定します。

key="target|platform|repo:revision"
hashname="hashmap"
declare -A $hashname

eval $hashname[$key]=0
echo $(eval $hashname[$key])

もちろん、最後の 2 行には問題があります。これは、eval が $key 変数内のパイプとコロンに作用しているためです。私の質問は、このような文字列を評価から保護するにはどうすればよいですか? また、ハッシュマップ自体ではなく、ハッシュマップの名前を参照しているため、eval が必要です。前もって感謝します。

================================================== ================================

わかりました、私の問題はパイプとコロンと eval にあるのではないと実際に考え始めています。それでは、実際のコードを貼り付けてみましょう

function print_hashmap()
{
    local hashname=$1
    for key in `eval echo \$\{\!$hashname[@]\}`; do
        local deref="$hashname[$key]"
        local value=${!deref}
        echo "key=${key} value=${value}"
    done
}
function create_permutations2()
{
    local hashname=$1   ; shift
    local builds=$1     ; shift
    local items=$1      ; shift
    local separators=$@

    echo "create_permutations(hashname=${hashname}, builds=${builds}, items=${items}, separators=${separators})"

    if [ NULL != "${builds}" ]; then
        for build in `echo $builds | tr ',' ' '`; do
            local target="${build%%:*}"
            local platforms="${build##*:}"
            for platform in `echo $platforms | tr '|' ' '`; do
                local key=
                local ref=
                if [ NULL != "${items}" ]; then
                    if [ NULL == "${separators}" ]; then separators=' '; fi
                    for separator in $separators; do
                        items=`echo $items | tr $separator ' '`
                    done
                    for item in $items; do
                        key="${target}|${platform}|${item}"
                        ref="$hashname[$key]"
                        declare "$ref"=0
                    done
                else
                    key="${target}|${platform}"
                    ref="$hashname[$key]"
                    declare "$ref"=0
                fi
            done
        done
    fi

    echo "created the following permutations:"
    print_hashmap $hashname
}
builds="k:r|s|w,l:r|s|w"
repos="c:master,m:master"
hashname="hashmap"
declare -A $hashname

create_permutations2 $hashname $builds $repos ","
print_hashmap $hashname

最近、eval の代わりに ref を使用するという FatalError の提案に準拠するようにコードを変更しましたが、エラーは同じです: 式の構文エラー (:master の近くのエラー トークン)

4

4 に答える 4

2

たぶん二重引用符で囲み$keyますか?

eval $hashname["$key"]=0
echo $(eval $hashname["$key"]=0)
于 2012-02-05T19:39:41.913 に答える
0

の悪さについては説明しませんがeval、この場合、少なくとも少し複雑になります。文字列の結果を評価しているため、私が考える最も簡単な方法は、リテラルの一重引用符をいくつか追加することです。

eval $hashname["'"$key"'"]=0

これにより、 の一重引用符を除くすべてが保護され$keyます。ただし、おそらく頭痛の種を減らして同じことを達成できます。説明するために更新したスクリプトを次に示します。

key="target|platform|repo:revision"
hashname="hashmap"
declare -A $hashname

echo "With eval:"
eval $hashname["'"$key"'"]=0
eval echo \${$hashname["'"$key"'"]}
echo

echo "Without eval:"
ref="$hashname[$key]"
echo ${!ref}
declare "$ref"="1"
echo ${!ref}

元の行は意味がわからなかったため、変更したことに注意してくださいeval。結果を印刷するのではなく、実行しようとしていました。後半では、インダイレクションを使用して値にアクセスし、declare代入することができます。そうすれば、これらの文字が解釈されることを心配する必要はありません。

これにより、次の結果が生成されます。

With eval:
0

Without eval:
0
1

それがうまくいかない理由は 100% わかりませんが、次のように思われます。

builds="k:r|s|w,l:r|s|w"
repos="c:master,m:master"
hashname="hashmap"
declare -A $hashname

function print_hashmap()
{
    local hashname=$1
    for key in `eval echo \$\{\!$hashname[@]\}`; do
        local deref="$hashname[$key]"
        local value=${!deref}
        echo "key=${key} value=${value}"
    done
}
function create_permutations2()
{
    local hashname=$1   ; shift
    local builds=$1     ; shift
    local items=$1      ; shift
    local separators=$@

    echo "create_permutations(hashname=${hashname}, builds=${builds}, items=${items}, separators=${separators})"

    if [ NULL != "${builds}" ]; then
        for build in `echo $builds | tr ',' ' '`; do
            local target="${build%%:*}"
            local platforms="${build##*:}"
            for platform in `echo $platforms | tr '|' ' '`; do
                local key=
                if [ NULL != "${items}" ]; then
                    if [ NULL == "${separators}" ]; then separators=' '; fi
                    for separator in $separators; do
                        items=`echo $items | tr $separator ' '`
                    done
                    for item in $items; do
                        key="${target}|${platform}|${item}"
                        ref="$hashname[$key]"
                        eval $hashname[\'$key\']=0
                    done
                else
                    key="${target}|${platform}"
                    eval $hashname[\'$key\']=0
                fi
            done
        done
    fi

    echo "created the following permutations:"
    print_hashmap $hashname
}

create_permutations2 $hashname $builds $repos ","
print_hashmap $hashname
于 2012-02-05T19:45:07.320 に答える
0

試す:

eval $hashname'[$key]'=0
eval result=$hashname'[$key]'

これは、最初にパラメーターを展開するのではなく、$に渡します。eval

于 2012-02-05T19:47:15.010 に答える