【问题标题】:Using Bash, is it possible to store an array in a dictionary使用 Bash,是否可以将数组存储在字典中
【发布时间】:2018-10-17 10:57:37
【问题描述】:

使用 bash,可以将数组存储在字典中吗?我已经展示了一些从字典中获取数组的示例代码,但它似乎失去了它是一个数组的事实。

我希望它是 dict+=(["pos"]="${array[@]}") 命令,但我不确定如何执行此操作,或者是否可能。

# Normal array behaviour (just an example)
array=(1 2 3)
for a in "${array[@]}"
do
    echo "$a"
done
# Outputs:
# 1
# 2
# 3

# Array in a dictionary
declare -A dict
dict+=(["pos"]="${array[@]}")

# When I fetch the array, it is not an array anymore
posarray=("${dict[pos]}")
for a in "${posarray[@]}"
do
    echo "$a"
done
# Outputs:
# 1 2 3
# but I want
# 1
# 2
# 3

【问题讨论】:

  • 如果你想在 shell 中支持这种级别的数据结构,你可能需要考虑ksh;否则,是时候考虑使用适当的通用编程语言了。在kshset -A foo; foo[k]=(1 2 3); echo ${foo[k][1]} 输出2

标签: arrays bash associative-array


【解决方案1】:

不,但有解决方法。


使用printf '%q ' + eval

您可以将数组展平为字符串:

printf -v array_str '%q ' "${array[@]}"
dict["pos"]=$array_str

...然后使用eval 将该数组扩展回来:

# WARNING: Only safe if array was populated with eval-safe strings, as from printf %q
key=pos; dest=array
printf -v array_cmd "%q=( %s )" "$dest" "${dict[$key]}"
eval "$array_cmd"

请注意,只有在使用printf '%q ' 代码填充关联数组以在添加值之前对其进行转义时,这才是安全的;避免此过程的内容可能对eval 不安全。


使用 base64 编码

更慢但更安全(如果您无法阻止不受信任的代码修改字典内容),另一种方法是存储 base64 编码的 NUL 分隔列表:

dict["pos"]=$(printf '%s\0' "${array[@]}" | openssl enc base64)

...并以同样的方式读出:

array=( )
while IFS= read -r -d '' item; do
  array+=( "$item" )
done < <(openssl enc -d base64 <<<"${dict["pos"]}"

使用多变量+间接扩展

这个实际上是对称的,尽管它需要 bash 4.3 或更高版本。也就是说,它将您的键名限制为允许作为 shell 变量名的键名。

key=pos
array=( "first value" "second value" )

printf -v var_name 'dict_%q' "$key"
declare -n var="$var_name"
var=( "${array[@]}" )
unset -n var

...之后declare -p dict_pos 将发出declare -a dict_pos=([0]="first value" [1]="second value")。另一方面,用于检索:

key=pos
printf -v var_name 'dict_%q' "$key"
declare -n var="$var_name"
array=( "${var[@]}" )
unset -n var

...之后declare -p array 将发出declare -a array=([0]="first value" [1]="second value")

【讨论】:

  • 感谢您解释第一个解决方法带来的危险。它对我有用,因为我可以控制输入。
【解决方案2】:

字典是关联数组,所以改写的问题是:“是否可以将一个数组存储在另一个数组中?”

不,不是。数组不能嵌套。

dict+=(["pos"]="${array[@]}")

为此,您需要一组额外的括号来将值捕获为数组而不是字符串:

dict+=(["pos"]=("${array[@]}"))

但这不是合法的语法。

【讨论】:

    猜你喜欢
    • 2016-10-21
    • 2018-07-19
    • 2014-04-30
    • 1970-01-01
    • 2014-04-14
    • 1970-01-01
    • 2016-09-17
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多