微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Bash:如何使用包含方括号或其他特殊字符的键来持久化和恢复关联数组

问题

为有效的Bash关联数组获取declare -p的结果,其中键包含方括号会导致错误的数组下标错误.

测试程序

做:

$declare -A array
$key='var[0]'
$array["$key"]=37
$echo ${array["$key"]}
37
$declare -p array > def.sh
$cat def.sh
declare -A array='(["var[0]"]="37" )'
$. def.sh
bash: [var[0]]=37: bad array subscript

在上面的代码中,请注意:

>我能够指定包含方括号的键:var [0]
>该密钥引用了setter和getter
>我可以使用此密钥进行分配
>我可以使用此键从关联数组中获取
>使用declare -p我可以将此定义保存到文件:def.sh
>在获取文件def.sh时会发出错误.

我的环境

>我正在使用的Bash版本是4.2.46(1)-release(x86_64-redhat-linux-gnu).
>我在CentOS 7.3.1611(核心)服务器上

解决方法

如果不是做声明-p array>我改为def.sh:

{
echo 'declare -A array'
for Key in "${!array[@]}"; do
   EscapedKey="$(sed 's|"|\\"|g' <<<"$Key")"
   echo "array[\"$EscapedKey\"]=${array["$Key"]}"
done
} > def.sh

然后采购def.sh文件.请注意,在上面的示例中,我还要转义可能是键的一部分的引号字符.我明白我上面所说的并不详尽.由于这些复杂性,如果可能的话,我宁愿选择不涉及此类变通方法解决方案.

是否有一些shopt,set -o< option>或其他我可以做的事情让我能够持久保存一个关联数组,其关键字可能包含方括号或其他特殊字符到文件中,以后能够成功获取文件?我需要一个在我的环境中工作的解决方案.

解决方法

这是一个错误

这是bash 4.2中的一个错误.它已在4.3中修复.

我通过从http://ftp.gnu.org/gnu/bash/编译bash 4.2,4.2.53和4.3来测试这个并复制了上面的步骤. 4.3表现得像4.4 – 没有这样的问题.然而,在bash 4.3中,声明将打印

declare -A array='(["var[0]"]="37" )'

就像4.2一样. 4.4不会在右侧添加引号,而是打印此:

declare -A array=(["var[0]"]="37" )

这与测试显示的结果没有区别.

在complete_fullquote中有一个可能相关的选项,但它在4.4中添加,因此它不能用作解决方法.

似乎除了使用版本> = 4.3之外,这需要解决,而您使用的版本是最简单的方法.

解决方法

如果你想避免使用sed调用(使用bash 4.2测试),还有另一种方法

function array2file {
  # local variable for the keys
  declare -a keys

  # check if the array exists,to protect against injection
  # by passing a crafted string
  declare -p "$1" >/dev/null || return 1;

  printf "declare -A %s\n" "$1"

  # create a string with all the keys so we can iterate
  # because we can't use eval at for's declaration
  # we do it this way to allow for spaces in the keys,since that's valid
  eval "keys=(\"\${!$1[@]}\")"

  for k in "${keys[@]}"
  do
    printf "%s[\"${k//\"/\\\\\"}\"]=" "$1"
    # the extra quoting here protects against spaces
    # within the element's value - injection doesn't work here
    # but we still need to make sure there's consistency
    eval "printf \"\\\"%s\\\"\n\" \"\${$1[\"${k//\"/\\\"}\"]}\""
  done
}

这将在键周围正确添加引号,并且还可以在键本身内转义所有双引号.您可以将其放在您提供的文件中.然后使用:

array2file array > ./def.sh

其中array是您选择的任何数组名称.通过重定向输出,您将获得正确引用的键,您可以像以前一样定义关联数组,然后将其传递给此函数进行存储.

额外的功劳

如果将for循环中第一个printf提供的变量从$1更改为${2: – $1}并在顶部的printf处执行相同操作,则可以选择使用第二个参数创建新数组的定义正如其名称,允许重命名.只有当您提供2个字符串而不是1个字符串时才会发生这种情况(当然引用).设置允许轻松完成,所以我在这里添加了它.

这可以让您解决使用预定义函数难以与现有代码进行交互的情况.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐