bash, eval, защищать трубы и двоеточие в строку - PullRequest
0 голосов
/ 05 февраля 2012

Вот самая простая версия моей проблемы. Сложность, которая остается, по веским причинам, даже если она не очевидна здесь. Кроме того, сценарий является внутренним и не имеет шансов на выполнение вредоносного кода, поэтому 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)

Ответы [ 3 ]

2 голосов
/ 05 февраля 2012

Возможно удваивает кавычки вокруг $key?

eval $hashname["$key"]=0
echo $(eval $hashname["$key"]=0)
0 голосов
/ 05 февраля 2012

Попробуйте:

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

Это передает $ в eval вместо того, чтобы сначала расширять параметр.

0 голосов
/ 05 февраля 2012

Я не буду читать лекции о зле 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
...