从BASH 4.4到4.2的backport“declare -n”

时间:2018-05-11 22:36:55

标签: bash

使用Bash 4.4,我使用“declare -n”编写了脚本,但今天我了解到,当我将这些脚本提供给RedHat 7用户时,脚本会因为BASH为4.2而失败。

这是一个小问题的例子,我想知道你是否可以建议我将这个方法反向移植到BASH 4.2:

#!/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表示声明不允许“-n”。

3 个答案:

答案 0 :(得分:1)

我认为您可以使用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[*]}

我在bash 4.2.37上对此进行了测试并获得了所需的输出

答案 1 :(得分:0)

它根本不干净,但您可以生成然后执行代码。为了确保生成安全,请使用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"
}

答案 2 :(得分:0)

我给@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
}

如果我有很多数组浮动,那么这种方法会变得乏味。

如果发生这种情况,我很确定我会回到依赖Bash 4.4的方法,并告诉那些老Bash的人他们必须升级或忘记它。我需要学习如何在脚本中添加代码来检测当前的Bash版本,如果不是4.3或更高版本则终止。我没有这样做,但可以。