0

这是我的问题的最简单的提炼版本。仍然存在的复杂性是有充分理由的,即使这里不明显。此外,脚本是内部的,没有机会执行恶意代码,因此 eval 非常好;不需要听到它有多邪恶...... ;) 假设密钥字符串中的管道和冒号是必需的分隔符。

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

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

当然最后两行有问题,因为 eval 作用于 $key 变量内的管道和冒号。我的问题是如何保护这样的字符串免受 eval 的影响?我需要 eval 因为我指的是 hashmap 的名称而不是它本身。提前致谢。

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

好的,我实际上开始认为我的问题不在于管道、冒号和 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

我最近修改了我的代码以符合 FatalError 使用 ref 而不是 eval 的建议,并且错误是相同的: 表达式中的语法错误(错误标记靠近: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 回答
0

对于这个小问题:“我的问题是如何保护这样的字符串免受 eval 的影响?”,我只会提到 bash 的“参数转换”(参见手册页)${parameter@operator},. 特别是,运算符 Q 计算为可以安全地用作输入的带引号的形式。

% echo ${key}
target|platform|repo:revision
% echo ${key@Q}
'target|platform|repo:revision'
于 2019-09-29T19:55:09.130 回答