我不确定我是否正确理解了你想要做的事情,尤其是“关联”部分(我看不到关联数组在哪里使用),但这段代码实现了我所理解的你想要做的事情:
#!/bin/bash
while IFS=" " read user time; do
eval "item=\${#$user[@]} ; $user[\$item]=\(\$((\$item + 1)),$time\)"
[[ "${arraynames[@]}" =~ $user ]] || arraynames[${#arraynames[@]}]=$user
done< <(sed -r 's/^ *([[:alnum:]]*) .*\((.*)\)$/\1 \2/')
for arrayname in ${arraynames[@]}; do
eval "array=(\${$arrayname[@]})"
echo "$arrayname has ${#array[@]} entries:"
for item in ${!array[@]}; do
echo "$arrayname[$item] = ${array[$item]}"
done
echo
done
它从标准输入读取。我已经使用像这样的示例文件进行了测试:
jww3321 pts/2 cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27 (00:58)
jpd8635 pts/1 cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49 (04:26)
jww3321 pts/2 cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27 (01:58)
jpd8635 pts/1 cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49 (05:26)
输出结果如下:
jww3321有两个条目:
jww3321[0] = (1,00:58)
jww3321[1] = (2,01:58)
jpd8635有两个条目:
jpd8635[0] = (1,04:26)
jpd8635[1] = (2,05:26)
请注意,仅使用标准整数索引数组。在Bash中,到目前为止,在左侧间接数组引用始终涉及使用eval(uuuuuuhhhh,幽灵般的声音),在右侧您可以通过${!}替换和命令替换$()轻松获得。
关于eval的经验法则:转义希望在eval时间扩展的内容,并且不要转义希望在eval时间之前扩展的内容。每当您对最终被评估的内容感到怀疑时,请复制该行并将eval更改为echo。
编辑:回答sarnold的评论,一种无需eval的方法:
#!/bin/bash
while IFS=" " read user time; do
array=$user[@] array=( ${!array} ) item=${#array[@]}
read $user[$item] <<< "\($(($item + 1)),$time\)"
[[ "${arraynames[@]}" =~ $user ]] || arraynames[${#arraynames[@]}]=$user
done< <(sed -r 's/^ *([[:alnum:]]*) .*\((.*)\)$/\1 \2/')
for arrayname in ${arraynames[@]}; do
array=$arrayname[@] array=( ${!array} )
echo "$arrayname has ${#array[@]} entries:"
for item in ${!array[@]}; do
echo "$arrayname[$item] = ${array[$item]}"
done
echo
done