Shell脚本中的关联数组


11

我看到了在Shell脚本中实现关联数组的技巧。例如print array["apples"],可以编写为echo \$array$keykey = apples。

但是,没有提到如何生成用于遍历数组的密钥。我能想到的唯一方法是将键存储在以空格分隔的变量中,以便可以使用for循环遍历数组。

因此,还有其他方法可以存储密钥以供以后使用吗?


5
如果您尝试在Shell脚本中使用关联数组,那么对于Shell脚本来说,您的项目可能太复杂了:)
Martin von Wittich 2014年

@MartinvonWittich为什么?我有一个Shell脚本,可以在3种可能的数据库模式之一中执行SQL脚本。所需的模式包含在文件名中,并带有缩写。我需要在此缩写和实际模式名称之间进行映射。考虑到实际的模式名称(不是缩写),哪种方法比关联数组更好,这在环境之间可能会有所不同,因此数组变量(其值只能设置一次)是完美的
Slav

2
@Slav我不是在反对关联数组,只是在需要这种复杂性的shell脚本中争论。但这只是我个人的喜好;我经常发现自己写了一个Shell脚本,然后当我意识到自己已经超过了一定的复杂性阈值时立即在Perl中重写了它。
2014年

Answers:


20

具有关联数组的壳

一些现代的shell提供了关联数组:ksh93,bash≥4,zsh。在ksh93和bash中,如果a是一个关联数组,则"${!a[@]}"是其键的数组:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

在zsh中,该语法仅在ksh仿真模式下有效。否则,您必须使用zsh的本机语法:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}如果a没有空键,也可以使用。

在zsh中,您还可以同时循环k遍历ey和alues v

for k v ("${(@kv)a}") echo "$k -> $v"

没有关联数组的外壳

在没有它们的shell中模拟关联数组需要做很多工作。如果需要关联数组,可能是时候引入更大的工具了,例如ksh93或Perl。

如果仅在POSIX外壳中确实需要关联数组,则当键被限制为仅包含字符0-9A-Z_a-z(ASCII数字,字母和下划线)时,这是一种模拟它们的方法。在这种假设下,键可以用作变量名的一部分。下面的函数作用于以命名前缀“ stem”标识的数组,该前缀不得包含两个连续的下划线。

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(警告,未经测试的代码。未提供语法无效的词干和键的错误检测。)


5

我不确定store的意思,但是可以使用以下${!array[@]}语法来遍历键:

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

因此,要迭代:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

我在这里找到了一个不错的简短教程。


如以下注释中所指出的,关联数组是在bash版本4 中添加的。有关主题的Linux期刊文章,请参见此处


1
(bash version 4 only)这是要注意的重要事项。传统上,bash数组仅是数字。
Ricky Beam

1
您可能要在示例中使用typeset而不是declare。那将使它们在bash 4和ksh93之间可移植,后者首先实现了shell关联数组。
jlliagre 2014年

0

没有关联数组的外壳

当键限制为[0-9A-Za-z_](数字,字母,下划线)时,这并不难。

诀窍不是存储到array [ $ key ] 而是存储到变量array_ $ key

组:

eval "array_$key='$value'"

得到:

value=`eval echo '$'array_$key`

注意:值不能包含'(单引号)。


-1

这在bash中起作用

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

要么

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

无需使用eval afaik


1
我相信您错过了问题的重点。
G-Man说'Resstate Monica''Mar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.