这是我问题的最简单的提炼版本。仍然存在的复杂性有充分的理由,即使这里不明显。此外,脚本是内部的,没有机会执行恶意代码,所以eval完全没问题。不需要知道它是多么邪恶......;)假设关键字符串中的管道和冒号是必需的分隔符。
key="target|platform|repo:revision"
hashname="hashmap"
declare -A $hashname
eval $hashname[$key]=0
echo $(eval $hashname[$key])
当然最后两行有问题,因为eval作用于$ key变量内部的管道和冒号。我的问题是如何从eval中保护这样的字符串?我需要eval因为我指的是hashmap的名字而不是它本身。提前谢谢。
=============================================== ===================================
好的,我实际上开始认为我的问题不在于管道,冒号和评估。所以让我粘贴真实的代码
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)
答案 0 :(得分:2)
可能在$key
周围加双引号?
eval $hashname["$key"]=0
echo $(eval $hashname["$key"]=0)
答案 1 :(得分: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
我不是百分之百确定为什么这不起作用,但这似乎是:
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
答案 2 :(得分:0)
尝试:
eval $hashname'[$key]'=0
eval result=$hashname'[$key]'
这会将$
传递给eval
,而不是先扩展参数。
答案 3 :(得分:0)
对于这小部分问题:“我的问题是如何保护这样的字符串免受评估?”,我只提到bash的“参数转换”(请参见手册页),${parameter@operator}
。特别是,运算符Q会得出可以安全用作输入的带引号的形式。
% echo ${key}
target|platform|repo:revision
% echo ${key@Q}
'target|platform|repo:revision'