“后端口”;声明-n“;从bash4.4到4.2
在Bash4.4中,我使用“declare-n”编写脚本,但今天我了解到,当我将这些脚本提供给Redhat7用户时,脚本会失败,因为他们的Bash是4.2 下面是一个小的问题示例,我想知道您是否可以给我提供一个好的方法,以便将此备份到BASH 4.2:“后端口”;声明-n“;从bash4.4到4.2,bash,Bash,在Bash4.4中,我使用“declare-n”编写脚本,但今天我了解到,当我将这些脚本提供给Redhat7用户时,脚本会失败,因为他们的Bash是4.2 下面是一个小的问题示例,我想知道您是否可以给我提供一个好的方法,以便将此备份到BASH 4.2: #!/bin/bash pwd=`pwd` declare -A parms parms[engine]=\"Sweave\" parms[verbose]=FALSE parms[tangle]=TRUE ## builds $parmst
#!/bin/bash
pwd=`pwd`
declare -A parms
parms[engine]=\"Sweave\"
parms[verbose]=FALSE
parms[tangle]=TRUE
## builds $parmstring by concatenating key=value pairs
catarr() {
declare -n __p="$1"
for k in "${!__p[@]}"
do parmstring+=", $k=${__p[$k]}"
done
}
parmstring=""
catarr parms
echo ${parmstring[*]}
输出应该是这样的:
$ bash bashmre.sh
, engine="Sweave", verbose=FALSE, tangle=TRUE
但在旧的BASH上,RedHat说declare不允许“-n”。它一点也不干净,但您可以生成并执行代码。为确保生成安全,请使用
printf%q
替换值
catarr() {
local eval_str
printf -v eval_str '
for k in "${!%q[@]}"; do
parmstring+=", $k=${%q[$k]}"
done
' "$1" "$1"
eval "$eval_str"
}
我认为您所寻找的可以通过
eval
实现:
#!/bin/bash
pwd=`pwd`
declare -A parms
parms[engine]=\"Sweave\"
parms[verbose]=FALSE
parms[tangle]=TRUE
## builds $parmstring by concatenating key=value pairs
catarr() {
eval keys=(\"\${!$1[@]}\")
for k in "${keys[@]}"
do
eval val=\${$1[$k]}
parmstring+=", $k=$val"
done
}
parmstring=""
catarr parms
echo ${parmstring[*]}
我在Bash4.2.37上测试了这个问题,得到了所需的输出我给@Charles Duffy和@shay的答案加了+1,但最后我没有使用这两个答案 我采取了查尔斯在我的原始帖子评论中建议的方法。我重新编写了这个东西,因此需要连接的每个数组都有一个单独的函数。在实际的应用程序中,我们正在使用它,有两个数组,“parms”和“myopts”,因此我最终得到了名为catparms和catmyopts的函数
catparms(){
for k in "${!parms[@]}"
do parmstring+=", $k=${parms[$k]}"
done
}
catmyopts(){
for k in "${!myopts[@]}"
do optstring+=", $k=${myopts[$k]}"
done
}
如果我有很多数组在周围浮动,那么这个方法就会变得单调乏味
如果发生这种情况,我很确定我会回到依赖bash4.4的方法,告诉那些使用旧Bash的人,他们必须升级,否则就忘了它。我需要学习如何在脚本中添加代码,以检测当前的Bash版本,并在它不是4.3或更高版本时终止。我没有做过,但是可以。如果你没有内置支持就可以获得该功能的效果,那么添加内置支持又有什么意义呢?顺便说一句,
paramstring+=“foo”
只是在paramstring[0]
后面追加,所以[*]
没有意义,您是否曾经将catar
用于除parms
以外的目标?如果没有,请硬编码数组名称,就完成了。谢谢。我不明白,但它是有效的,所以对我来说是+1。我希望在座的其他人投票,帮助选择正确的答案。你能看看@shay的建议吗?我觉得还可以。你有什么意见吗?我在一篇评论中注意到shay的答案中有一个错误,但这很容易修复(通过添加额外的引号)。这种方法的更大问题(在不转义的情况下将$1
替换为eval
的字符串)是通过恶意变量名进行代码注入——如果有人运行catar'}foo[@]});运行任意命令;#'代码>,此版本只会抛出一个错误,并且该版本将运行所选的任意命令。如果攻击者无论如何都可以运行任意命令,那么这不是一个风险,但是如果您正在从正在读取的数据(文件名等)生成变量名,那么这就是一个风险。请参阅针对其他代码的成功代码注入攻击的示例,即使使用额外的引号进行编辑;与之相比,对该答案尝试相同的攻击,该答案会发出语法错误,但实际上不会运行有效负载。需要在eval
'd字符串中加引号——现在您正在运行keys=(${!parms[@]})
,这是不正确的;它需要是keys=(“${!parms[@]}”)
才能正确处理所有可能的键。使用parms[“扩展键”]=“两个单词”
进行测试更好。我建议让它只echo“$parmstring”
——因为字符串只是一个字符串而不是一个数组,所以没有必要将其视为后者——但这只是一种诡辩。我同意。我只是想尽可能少地修改示例脚本