我们需要一个模拟关联数组的脚本或类似于Shell Scripting的数据结构的Map,任何主体?
如果可移植性不是您主要关注的另一个选择,则使用内置于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]}
根据shell的不同,您可能需要typeset -A newmap
代替declare -A newmap
,或者在某些情况下可能根本不需要.
另一种非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"
你也可以在那里抛出一个if语句进行搜索.if [[$ var =〜/ blah /]].管他呢.
我认为你需要退一步思考一下地图或关联数组究竟是什么.它只是一种存储给定键值的方法,可以快速有效地恢复该值.您可能还希望能够遍历密钥以检索每个键值对,或删除键及其关联值.
现在,考虑一下您在shell脚本中一直使用的数据结构,甚至只是在没有编写脚本的shell中,它具有这些属性.难倒?这是文件系统.
真的,你需要在shell编程中拥有一个关联数组就是一个临时目录.mktemp -d
是你的关联数组构造函数:
prefix=$(basename -- "$0") map=$(mktemp -dt ${prefix}) echo >${map}/key somevalue value=$(cat ${map}/key)
如果您不想使用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
编辑:这种方法实际上比使用提问者建议的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
结果:
$ 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
要添加Irfan的答案,这里是一个更短更快的版本,get()
因为它不需要迭代地图内容:
get() { mapName=$1; key=$2 map=${!mapName} value="$(echo $map |sed -e "s/.*--${key}=\([^ ]*\).*/\1/" -e 's/:SP:/ /g' )" }
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
Bash4原生支持这一点.不要使用grep
或eval
,他们是最丑陋的黑客.
有关示例代码的详细详细答案,请参阅:https: //stackoverflow.com/questions/3467959
#################################################################### # 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; }' }
例:
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