如何无eval反序列化${aa[@]@K}到关联数组并重赋值
Bash中关联数组的引用与${parameter@K}序列化字符串的反序列化(避免eval的尝试)
问题说明
需要实现:通过${parameter@K}生成的序列化字符串(来自外部,比如文件读取,实际场景中无原数组变量),将内容赋值给通过declare -n引用的关联数组,目标是避免使用eval。
${parameter@K}生成参数值的带引号版本,对关联数组会输出带引号的键值对序列。
初始测试代码
#!/bin/bash func() { declare -n aa=$1 # `aa=()`可用于清空引用数组后填充,此处省略以观察引用丢失情况 # 实际代码中仅serialized字符串可用 declare -A aa_original=("a" "3" "b" "4") serialized=$(printf '%s' "${aa_original[@]@K}") aa="( $serialized )" # 以下仅用于调试 echo "~ at the end of func() now" echo "~ serialized: $serialized" echo "~ aa_original:" for key in "${!aa_original[@]}"; do printf "%s->%s " $key ${aa_original[$key]}; done echo echo "~ aa:" for key in "${!aa[@]}"; do printf "%s->%s " $key ${aa[$key]}; done echo echo "~ leaving func() now" } declare -A AA=("a" "1" "b" "2") func AA echo "${AA["a"]} ~ ${AA["b"]}"
预期最终输出3 ~ 4,实际输出1 ~ 2,全局数组AA被破坏,调试输出如下:
~ at the end of func() now ~ serialized: b "4" a "3" ~ aa_original: b->4 a->3 ~ aa: 0->( b->"4" a->"3" )-> b->2 a->1 ~ leaving func() now
尝试显式声明declare -A的问题
修改赋值语句为:
declare -A aa="( $serialized )"
赋值成功,但丢失了declare -n的引用属性,调试输出如下:
~ at the end of func() now ~ serialized: b "4" a "3" ~ aa_original: b->4 a->3 ~ aa: b->4 a->3 ~ leaving func() now 1 ~ 2
可行解决方案
方案1:临时本地数组中转
通过创建临时本地数组接收序列化内容,再遍历填充到引用数组中:
#!/bin/bash func() { declare -n aa=$1 serialized=$(declare -A aa_original=("a" "3" "b" "4"); printf '%s' "${aa_original[@]@K}") # 创建临时本地数组 declare -A aa_local="( $serialized )" # 清空并重新填充引用数组 aa=() for key in "${!aa_local[@]}"; do aa["$key"]="${aa_local[$key]}"; done } declare -A AA=("a" "1" "b" "2") func AA echo "${AA["a"]} ~ ${AA["b"]}"
方案2:简化的eval方案
经提示,上述中转方案与直接使用eval等效,以下是更简洁的实现,支持${parameter@K}输出的$'...'ANSI-C引号结构:
#!/bin/bash func() { declare -n aa=$1 serialized=$(declare -A aa_original=("a" "3" "b" "4"); printf '%s' "${aa_original[@]@K}") aa=() eval aa="( $serialized )" } declare -A AA=("a" "1" "b" "2") func AA echo "${AA["a"]} ~ ${AA["b"]}"
目前针对${parameter@K}的输出,无eval的实现无法完成需求,上述方案是当前最优解。
内容的提问来源于stack exchange,提问作者Albert Camu
相关产品推荐
相关产品推荐

