Bash关联数组,值为列表

18

我必须使用Java工具的输出,它返回一个类似于HashMap<String, ArrayList<String>的映射数据结构。我必须使用BASH,并尝试将其声明为关联数组,这非常类似于映射。在BASH中声明关联数组应该在一行中完成,我尝试如下操作。

ARRAY=(["sem1"]=("first name" "second name") ["sem2"]=("third name") ["sem3]=OTHER_LITS)

但是这会导致以下错误:

bash: syntax error near unexpected token `('
我可以逐行定义该行,但我想让它变成一行。如何在Bash中仅用一行定义关联数组?

Bash中没有映射/字典功能吗??? - Oni1
2
BASH中没有多维数组。 - anubhava
有什么建议可以解决我的问题吗? - Oni1
2
你还没有解释问题。为什么需要多维数组?你想做什么? - anubhava
我正在使用一个Java工具获得输出,它是一个Map数据结构。我需要在Bash环境中处理这个Map。 - Oni1
你能否在回答中解决它? - Oni1
3个回答

22

顺便提一下,关联数组、字典或映射都属于同一种抽象数据类型(我们称之为字典)。

那么,这里是将数组作为Bash(4+版本)中的字典值存储的解决方案。

请注意,在Bash中,数组是一个由空格分隔的字符串列表(因此不包含任何元素内部的空格),因此我们可以将带引号的列表:

"firstname middlename secondname"

作为X字典中s1键的值:

declare -A X=(
  ['s1']="firstname middlename secondname"
  ['s2']="surname nickname"
  ['s3']="other"
)

现在我们可以将s1键的值作为数组获取:

declare -a names=(${X[s1]})

变量names现在包含一个数组

> echo $names
firstname

> echo ${names[1]}
middlename

> echo ${#names[@]}
3

最后,你提到了一个包含空格的字符串的问题:

"first name""second name"

我们可以使用一个技巧 - 把一个 空格 表示为一个特殊的符号序列(可以只是一个符号),例如双下划线:

"first__name""second__name"

重新声明我们的字典,但在数组元素中用"转义"空格:

declare -A X=(
  ['s1']="first__name middle__name second__name"
  ['s2']="surname nickname"
  ['s3']="other"
)
在这种情况下,当我们得到s1键的值为数组后: declare -a names=(${X[s1]}) 我们需要对数组元素进行后处理,以删除__代表空格替换为实际的空格符号。为了做到这一点,我们只需要使用Bash字符串的替换命令即可。
> echo ${names/__/ }
first name

> echo ${names[1]/__/ }
middle name

> echo ${#names[@]}
3

1
这是一个杰出的解决方案。 - RonJohn
对于我使用的bash 5.0.17(1)-release,这个方法并没有起作用。echo $names输出“firstname middlename secondname”。 - Patrick

5

由于BASH不支持多维数组,因此您可以使用这个变通的关联数组。关联数组中的每个key是map-index,array-list-index字符串拼接而成:

# use one line declaration
declare -A array=([sem1,0]="first name" [sem1,1]="second name" [sem2,0]="third name" [sem3,0]="foo bar")

# loop thrpugh the map array
for i in "${!array[@]}"; do echo "$i => ${array[$i]}"; done
sem2,0 => third name
sem1,0 => first name
sem1,1 => second name
sem3,0 => foo bar

2
呵呵,这很聪明。 - Peter M. Elias

1
一种更符合人体工程学的解决方案,不会强制操作按键。
# your data with spaces
array=(1 '2 with space' 3 "4 with space and ' symbol")
declare -p array

# quote it with " and store it, your data can't contain double quote
declare -A associative=([x]=x [array]=$(printf '"%s" ' "${array[@]}"))
declare -p associative

# get your data in another array
eval deserialized_array=(${associative[array]})
declare -p deserialized_array

echo ${deserialized_array[3]}

# or let bash handle everything

# note: array contain data with double quote character
array=(1 '2 with space' 3 "4 with space and ' \" symbol")

declare -A associative=([x]=x [array]=$(declare -p array))
declare -p associative

array=() # make sure data is gone

# get the data in the same array 
eval ${associative[array]}
echo ${array[3]}

不错的技巧。但是如果没有旨在真正教育读者的解释,这并不是很有帮助。 - huyz
@huyz,你需要更详细地解释OT问题的哪一部分以及解释代码正在做什么的评论? - Nadim Khemir
在你编辑答案并添加评论之前,我写了那个问题。现在答案很好。 - huyz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接