Shell 脚本中的关联数组

Egg*_*ead 11 shell-script associative-array

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

但是,没有提到如何生成键来迭代数组。我能想到的唯一方法是将键存储在一个由空格分隔的变量中,这样我就可以使用 for 循环来遍历数组。

那么,是否有其他方法可以存储密钥以备后用?

Gil*_*il' 20

带有关联数组的壳

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

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done
Run Code Online (Sandbox Code Playgroud)

在 zsh 中,该语法仅适用于 ksh 仿真模式。否则你必须使用 zsh 的原生语法:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done
Run Code Online (Sandbox Code Playgroud)

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

在 zsh 中,您还可以同时在keys 和 alues上循环v

for k v ("${(@kv)a}") echo "$k -> $v"
Run Code Online (Sandbox Code Playgroud)

没有关联数组的壳

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

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

## 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"
}
Run Code Online (Sandbox Code Playgroud)

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


ter*_*don 5

我不确定您所说的 store 是什么意思,但您可以使用以下${!array[@]}语法迭代键:

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

所以,要迭代:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar
Run Code Online (Sandbox Code Playgroud)

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


正如在下面的评论中指出的那样,在bash第 4 版中添加了关联数组。 有关该主题的 Linux 期刊文章,请参见此处

  • `(仅限 bash 版本 4)` 这是需要注意的重要事项。传统上,“bash”数组只是数字。 (2认同)