什么是Python字典的等效,但在Bash中(应该适用于OS X和Linux)。
当前回答
在bash 4之前,在bash中没有使用关联数组的好方法。最好的办法是使用一种真正支持这些功能的解释语言,比如awk。另一方面,bash 4确实支持它们。
至于bash 3中不太好的方法,这里有一个参考:http://mywiki.wooledge.org/BashFAQ/006
其他回答
有两件事,在任何2.6内核中使用/dev/shm (Redhat)都可以使用内存而不是/tmp,其他发行版可能会有所不同。hget也可以用read重新实现,如下所示:
function hget {
while read key idx
do
if [ $key = $2 ]
then
echo $idx
return
fi
done < /dev/shm/hashmap.$1
}
此外,通过假设所有键都是唯一的,返回值会使读循环短路,从而避免读取所有条目。如果您的实现可以有重复的键,那么只需省略返回。这节省了读取和派生grep和awk的开销。在这两个实现中使用/dev/shm会在3个条目的散列上使用time hget来搜索最后一个条目:
握把/卒:
hget() {
grep "^$2 " /dev/shm/hashmap.$1 | awk '{ print $2 };'
}
$ time echo $(hget FD oracle)
3
real 0m0.011s
user 0m0.002s
sys 0m0.013s
Read / echo:
$ time echo $(hget FD oracle)
3
real 0m0.004s
user 0m0.000s
sys 0m0.004s
在多次调用中,我从未看到过低于50%的改善。 这都是由于使用了/dev/shm.而导致的
考虑使用bash内置read的解决方案,如下面的ufw防火墙脚本代码片段所示。这种方法的优点是可以根据需要使用尽可能多的带分隔符的字段集(不只是2个)。我们使用了|分隔符,因为端口范围说明符可能需要冒号,即6001:6010。
#!/usr/bin/env bash
readonly connections=(
'192.168.1.4/24|tcp|22'
'192.168.1.4/24|tcp|53'
'192.168.1.4/24|tcp|80'
'192.168.1.4/24|tcp|139'
'192.168.1.4/24|tcp|443'
'192.168.1.4/24|tcp|445'
'192.168.1.4/24|tcp|631'
'192.168.1.4/24|tcp|5901'
'192.168.1.4/24|tcp|6566'
)
function set_connections(){
local range proto port
for fields in ${connections[@]}
do
IFS=$'|' read -r range proto port <<< "$fields"
ufw allow from "$range" proto "$proto" to any port "$port"
done
}
set_connections
下面是一个相当做作但希望有指导意义的哈希/映射/字典/关联数组示例。假设我有一个字符串数组,我想创建一个映射,从每个单词到它在数组中出现的次数。
当然,有很多方法可以使用管道命令来实现这一点,但重点是演示核心的映射操作:使用-v检查键的存在性、添加键-值映射、检索键的值、更新键的现有值以及遍历整个映射以打印键-值对。
#!/usr/bin/bash
set -o pipefail
bash --version | head -1
words=(foo foo bar bar foo baz baz foo bar)
declare -A counter=() # create the map
for word in "${words[@]}"; do
# if the key doesn't yet exist in the map, add it
if [[ ! -v counter[$word] ]]; then
counter[$word]=0
fi
# look up the value of a key, add one, and store back in the map
counter[$word]=$((${counter[$word]} + 1))
done
# iterate the map
for key in "${!counter[@]}"; do
echo "$key ${counter[$key]}"
done
输出:
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
foo 4
bar 3
baz 2
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
我真的很喜欢Al P的答案,但想要唯一性强制廉价,所以我更进一步-使用目录。有一些明显的限制(目录文件限制,无效的文件名),但它应该适用于大多数情况。
hinit() {
rm -rf /tmp/hashmap.$1
mkdir -p /tmp/hashmap.$1
}
hput() {
printf "$3" > /tmp/hashmap.$1/$2
}
hget() {
cat /tmp/hashmap.$1/$2
}
hkeys() {
ls -1 /tmp/hashmap.$1
}
hdestroy() {
rm -rf /tmp/hashmap.$1
}
hinit ids
for (( i = 0; i < 10000; i++ )); do
hput ids "key$i" "value$i"
done
for (( i = 0; i < 10000; i++ )); do
printf '%s\n' $(hget ids "key$i") > /dev/null
done
hdestroy ids
在我的测试中,它的表现也稍微好一点。
$ time bash hash.sh
real 0m46.500s
user 0m16.767s
sys 0m51.473s
$ time bash dirhash.sh
real 0m35.875s
user 0m8.002s
sys 0m24.666s
我只是想帮帮忙。干杯!
编辑:添加hdestroy()