Irf*_*qar 112 bash shell associative-array hashtable
我们需要一个模拟关联数组的脚本或类似于Shell Scripting的数据结构的Map,任何主体?
Bri*_*ell 143
如果可移植性不是您主要关注的另一个选择,则使用内置于shell的关联数组.这应该适用于bash 4.0(现在大多数主要发行版都可用,但不是在OS X上,除非你自己安装),ksh和zsh:
declare -A newmap
newmap[name]="Irfan Zulfiqar"
newmap[designation]=SSE
newmap[company]="My Own Company"
echo ${newmap[company]}
echo ${newmap[name]}
Run Code Online (Sandbox Code Playgroud)
根据shell的不同,您可能需要typeset -A newmap代替declare -A newmap,或者在某些情况下可能根本不需要.
Bub*_*off 87
另一种非bash 4种方式.
#!/bin/bash
# A pretend Python dictionary with bash 3
ARRAY=( "cow:moo"
"dinosaur:roar"
"bird:chirp"
"bash:rock" )
for animal in "${ARRAY[@]}" ; do
KEY=${animal%%:*}
VALUE=${animal#*:}
printf "%s likes to %s.\n" "$KEY" "$VALUE"
done
echo -e "${ARRAY[1]%%:*} is an extinct animal which likes to ${ARRAY[1]#*:}\n"
Run Code Online (Sandbox Code Playgroud)
你也可以在那里抛出一个if语句进行搜索.if [[$ var =〜/ blah /]].管他呢.
Bri*_*ell 32
我认为你需要退一步思考一下地图或关联数组究竟是什么.它只是一种存储给定键值的方法,可以快速有效地恢复该值.您可能还希望能够遍历密钥以检索每个键值对,或删除键及其关联值.
现在,考虑一下您在shell脚本中一直使用的数据结构,甚至只是在没有编写脚本的shell中,它具有这些属性.难倒?这是文件系统.
真的,你需要在shell编程中拥有一个关联数组就是一个临时目录.mktemp -d是你的关联数组构造函数:
prefix=$(basename -- "$0")
map=$(mktemp -dt ${prefix})
echo >${map}/key somevalue
value=$(cat ${map}/key)
Run Code Online (Sandbox Code Playgroud)
如果您不想使用echo和cat,您可以随时写一些小包装; 这些是以Irfan为模型的,虽然它们只是输出值而不是设置任意变量,如$value:
#!/bin/sh
prefix=$(basename -- "$0")
mapdir=$(mktemp -dt ${prefix})
trap 'rm -r ${mapdir}' EXIT
put() {
[ "$#" != 3 ] && exit 1
mapname=$1; key=$2; value=$3
[ -d "${mapdir}/${mapname}" ] || mkdir "${mapdir}/${mapname}"
echo $value >"${mapdir}/${mapname}/${key}"
}
get() {
[ "$#" != 2 ] && exit 1
mapname=$1; key=$2
cat "${mapdir}/${mapname}/${key}"
}
put "newMap" "name" "Irfan Zulfiqar"
put "newMap" "designation" "SSE"
put "newMap" "company" "My Own Company"
value=$(get "newMap" "company")
echo $value
value=$(get "newMap" "name")
echo $value
Run Code Online (Sandbox Code Playgroud)
编辑:这种方法实际上比使用提问者建议的sed的线性搜索快得多,而且更健壮(它允许键和值包含 - ,=,space,qnd":SP:").它使用文件系统的事实并没有使它变慢; 除非你打电话sync,否则这些文件实际上永远不会保证写入磁盘; 对于这样的临时文件,如果生命周期很短,那么它们中的许多文件永远不会被写入磁盘.
我使用以下驱动程序对Irfan的代码,Jerry修改Irfan的代码和我的代码做了一些基准测试:
#!/bin/sh
mapimpl=$1
numkeys=$2
numvals=$3
. ./${mapimpl}.sh #/ <- fix broken stack overflow syntax highlighting
for (( i = 0 ; $i < $numkeys ; i += 1 ))
do
for (( j = 0 ; $j < $numvals ; j += 1 ))
do
put "newMap" "key$i" "value$j"
get "newMap" "key$i"
done
done
Run Code Online (Sandbox Code Playgroud)
结果:
$ time ./driver.sh irfan 10 5
real 0m0.975s
user 0m0.280s
sys 0m0.691s
$ time ./driver.sh brian 10 5
real 0m0.226s
user 0m0.057s
sys 0m0.123s
$ time ./driver.sh jerry 10 5
real 0m0.706s
user 0m0.228s
sys 0m0.530s
$ time ./driver.sh irfan 100 5
real 0m10.633s
user 0m4.366s
sys 0m7.127s
$ time ./driver.sh brian 100 5
real 0m1.682s
user 0m0.546s
sys 0m1.082s
$ time ./driver.sh jerry 100 5
real 0m9.315s
user 0m4.565s
sys 0m5.446s
$ time ./driver.sh irfan 10 500
real 1m46.197s
user 0m44.869s
sys 1m12.282s
$ time ./driver.sh brian 10 500
real 0m16.003s
user 0m5.135s
sys 0m10.396s
$ time ./driver.sh jerry 10 500
real 1m24.414s
user 0m39.696s
sys 0m54.834s
$ time ./driver.sh irfan 1000 5
real 4m25.145s
user 3m17.286s
sys 1m21.490s
$ time ./driver.sh brian 1000 5
real 0m19.442s
user 0m5.287s
sys 0m10.751s
$ time ./driver.sh jerry 1000 5
real 5m29.136s
user 4m48.926s
sys 0m59.336s
Jer*_*ner 20
要添加Irfan的答案,这里是一个更短更快的版本,get()因为它不需要迭代地图内容:
get() {
mapName=$1; key=$2
map=${!mapName}
value="$(echo $map |sed -e "s/.*--${key}=\([^ ]*\).*/\1/" -e 's/:SP:/ /g' )"
}
Run Code Online (Sandbox Code Playgroud)
Dig*_*oss 15
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`
Run Code Online (Sandbox Code Playgroud)
$ sh hash.sh
Paris and Amsterdam and Madrid
Run Code Online (Sandbox Code Playgroud)
另一种非 bash-4(即 bash 3,Mac 兼容)方式:
val_of_key() {
case $1 in
'A1') echo 'aaa';;
'B2') echo 'bbb';;
'C3') echo 'ccc';;
*) echo 'zzz';;
esac
}
for x in 'A1' 'B2' 'C3' 'D4'; do
y=$(val_of_key "$x")
echo "$x => $y"
done
Run Code Online (Sandbox Code Playgroud)
印刷:
A1 => aaa
B2 => bbb
C3 => ccc
D4 => zzz
Run Code Online (Sandbox Code Playgroud)
带有 的函数case就像一个关联数组。不幸的是它不能使用return,所以它必须echo输出,但这不是问题,除非你是一个避免分叉子 shell 的纯粹主义者。
Bash4原生支持这一点.不要使用grep或eval,他们是最丑陋的黑客.
有关示例代码的详细详细答案,请参阅:https: //stackoverflow.com/questions/3467959
小智 6
####################################################################
# Bash v3 does not support associative arrays
# and we cannot use ksh since all generic scripts are on bash
# Usage: map_put map_name key value
#
function map_put
{
alias "${1}$2"="$3"
}
# map_get map_name key
# @return value
#
function map_get
{
alias "${1}$2" | awk -F"'" '{ print $2; }'
}
# map_keys map_name
# @return map keys
#
function map_keys
{
alias -p | grep $1 | cut -d'=' -f1 | awk -F"$1" '{print $2; }'
}
Run Code Online (Sandbox Code Playgroud)
例:
mapName=$(basename $0)_map_
map_put $mapName "name" "Irfan Zulfiqar"
map_put $mapName "designation" "SSE"
for key in $(map_keys $mapName)
do
echo "$key = $(map_get $mapName $key)
done
Run Code Online (Sandbox Code Playgroud)
对于 Bash 3,有一种特殊情况有一个很好且简单的解决方案:
如果您不想处理大量变量,或者键只是无效的变量标识符,并且您的数组保证少于 256 个项目,则可以滥用函数返回值。该解决方案不需要任何子 shell,因为该值可以随时作为变量使用,也不需要任何迭代,因此性能极高。而且它的可读性非常好,几乎就像 Bash 4 版本一样。
这是最基本的版本:
hash_index() {
case $1 in
'foo') return 0;;
'bar') return 1;;
'baz') return 2;;
esac
}
hash_vals=("foo_val"
"bar_val"
"baz_val");
hash_index "foo"
echo ${hash_vals[$?]}
Run Code Online (Sandbox Code Playgroud)
请记住,在 中使用单引号case,否则可能会出现通配符。从一开始对于静态/冻结哈希确实很有用,但是可以从hash_keys=()数组编写索引生成器。
请注意,它默认为第一个元素,因此您可能需要保留第零个元素:
hash_index() {
case $1 in
'foo') return 1;;
'bar') return 2;;
'baz') return 3;;
esac
}
hash_vals=("", # sort of like returning null/nil for a non existent key
"foo_val"
"bar_val"
"baz_val");
hash_index "foo" || echo ${hash_vals[$?]} # It can't get more readable than this
Run Code Online (Sandbox Code Playgroud)
警告:长度现在不正确。
或者,如果您想保留从零开始的索引,您可以保留另一个索引值并防止不存在的键,但它的可读性较差:
hash_index() {
case $1 in
'foo') return 0;;
'bar') return 1;;
'baz') return 2;;
*) return 255;;
esac
}
hash_vals=("foo_val"
"bar_val"
"baz_val");
hash_index "foo"
[[ $? -ne 255 ]] && echo ${hash_vals[$?]}
Run Code Online (Sandbox Code Playgroud)
或者,为了保持长度正确,将索引偏移一:
hash_index() {
case $1 in
'foo') return 1;;
'bar') return 2;;
'baz') return 3;;
esac
}
hash_vals=("foo_val"
"bar_val"
"baz_val");
hash_index "foo" || echo ${hash_vals[$(($? - 1))]}
Run Code Online (Sandbox Code Playgroud)