什么是Python字典的等效,但在Bash中(应该适用于OS X和Linux)。
当前回答
我也使用了bash4的方式,但我发现了一个恼人的bug。
我需要动态更新关联数组内容,所以我使用这种方式:
for instanceId in $instanceList
do
aws cloudwatch describe-alarms --output json --alarm-name-prefix $instanceId| jq '.["MetricAlarms"][].StateValue'| xargs | grep -E 'ALARM|INSUFFICIENT_DATA'
[ $? -eq 0 ] && statusCheck+=([$instanceId]="checkKO") || statusCheck+=([$instanceId]="allCheckOk"
done
我发现,与bash 4.3.11附加到字典中的现有键导致附加值,如果已经存在。例如,在一些重复之后,值的内容是“checkKOcheckKOallCheckOK”,这是不好的。
使用bash 4.3.39没有问题,其中附加一个存在的键意味着替换已经存在的实际值。
我解决了这个问题,只是在循环之前清洗/声明statusCheck关联数组:
unset statusCheck; declare -A statusCheck
其他回答
hput () {
eval hash"$1"='$2'
}
hget () {
eval echo '${hash'"$1"'#hash}'
}
hput France Paris
hput Netherlands Amsterdam
hput Spain Madrid
echo `hget France` and `hget Netherlands` and `hget Spain`
$ sh hash.sh
Paris and Amsterdam and Madrid
在bash 4之前,在bash中没有使用关联数组的好方法。最好的办法是使用一种真正支持这些功能的解释语言,比如awk。另一方面,bash 4确实支持它们。
至于bash 3中不太好的方法,这里有一个参考:http://mywiki.wooledge.org/BashFAQ/006
Bash 4
Bash 4本身支持这个特性。确保脚本的hashbang是#!/usr/bin/env bash或#!/bin/bash,这样你就不会使用sh。确保你要么直接执行你的脚本,要么用bash脚本执行脚本。(没有实际使用Bash执行Bash脚本的情况确实会发生,这将非常令人困惑!)
你可以这样声明一个关联数组:
declare -A animals
可以使用普通数组赋值操作符将其填充为元素。例如,如果你想要一个animal[sound(key)] = animal(value)的映射:
animals=( ["moo"]="cow" ["woof"]="dog")
或者在一行中声明和实例化:
declare -A animals=( ["moo"]="cow" ["woof"]="dog")
然后像普通数组一样使用它们。使用
Animals ['key']='value'设置值 ${animals[@]}展开值 “$ {!animals[@]}”(注意!)来展开键
别忘了引用他们的话:
echo "${animals[moo]}"
for sound in "${!animals[@]}"; do echo "$sound - ${animals[$sound]}"; done
Bash 3
在bash 4之前,没有关联数组。不要使用eval来模拟它们。像避免瘟疫一样避免eval,因为它是shell脚本的瘟疫。最重要的原因是eval将数据视为可执行代码(还有许多其他原因)。
首先也是最重要的:考虑升级到bash 4。这将使整个过程对你来说容易得多。
如果有不能升级的原因,声明是一个更安全的选择。它不像bash代码那样像eval那样计算数据,因此不允许如此容易地进行任意代码注入。
让我们通过介绍概念来准备答案:
首先,间接。
$ animals_moo=cow; sound=moo; i="animals_$sound"; echo "${!i}"
cow
其次,声明:
$ sound=moo; animal=cow; declare "animals_$sound=$animal"; echo "$animals_moo"
cow
把它们放在一起:
# Set a value:
declare "array_$index=$value"
# Get a value:
arrayGet() {
local array=$1 index=$2
local i="${array}_$index"
printf '%s' "${!i}"
}
让我们使用它:
$ sound=moo
$ animal=cow
$ declare "animals_$sound=$animal"
$ arrayGet animals "$sound"
cow
注意:declare不能放在函数中。在bash函数中使用declare将其创建的变量转换为该函数范围内的局部变量,这意味着我们不能使用它访问或修改全局数组。(在bash 4中,您可以使用declare -g来声明全局变量——但在bash 4中,您可以首先使用关联数组,从而避免这种变通方法。)
简介:
升级到bash 4并对关联数组使用declare -A。 如果不能升级,请使用声明选项。 可以考虑使用awk,并完全避免这个问题。
我同意@lhunath和其他人的观点,关联数组是Bash 4的首选。如果你坚持使用Bash 3 (OSX,你不能更新的旧发行版),你也可以使用expr,它应该无处不在,一个字符串和正则表达式。我喜欢它,尤其是当字典不是太大。
Choose 2 separators that you will not use in keys and values (e.g. ',' and ':' ) Write your map as a string (note the separator ',' also at beginning and end) animals=",moo:cow,woof:dog," Use a regex to extract the values get_animal { echo "$(expr "$animals" : ".*,$1:\([^,]*\),.*")" } Split the string to list the items get_animal_items { arr=$(echo "${animals:1:${#animals}-2}" | tr "," "\n") for i in $arr do value="${i##*:}" key="${i%%:*}" echo "${value} likes to $key" done }
现在你可以使用它:
$ animal = get_animal "moo"
cow
$ get_animal_items
cow likes to moo
dog likes to woof
Bash 3解决方案:
在阅读一些答案的过程中,我整理了一个快速的小函数,我想贡献出来,可能会帮助到其他人。
# Define a hash like this
MYHASH=("firstName:Milan"
"lastName:Adamovsky")
# Function to get value by key
getHashKey()
{
declare -a hash=("${!1}")
local key
local lookup=$2
for key in "${hash[@]}" ; do
KEY=${key%%:*}
VALUE=${key#*:}
if [[ $KEY == $lookup ]]
then
echo $VALUE
fi
done
}
# Function to get a list of all keys
getHashKeys()
{
declare -a hash=("${!1}")
local KEY
local VALUE
local key
local lookup=$2
for key in "${hash[@]}" ; do
KEY=${key%%:*}
VALUE=${key#*:}
keys+="${KEY} "
done
echo $keys
}
# Here we want to get the value of 'lastName'
echo $(getHashKey MYHASH[@] "lastName")
# Here we want to get all keys
echo $(getHashKeys MYHASH[@])