Bash:计算关联数组中键的总数吗?

问题描述

考虑下面的关联数组:

declare -A shapingTimes
 shapingTimes=([0-start]=15 [0-stop]=21 [0-anotherkey]=foo)
shapingTimes+=([1-start]=4  [1-stop]=6  [1-anotherkey]=bar)
shapingTimes+=([2-start]=9  [2-stop]=11 [2-anotherkey]=blah)

是否可以找到数组中每个条目使用的键总数? (这是数组中的每个“索引”吗?)

例如,如何计算:[开始],[停止],[另一个键] = 3个键?

此刻,我正在使用此代码中的硬编码值(3)(如下所示)可以完成这项工作,但是我想知道是否可以动态实现?

totalshapingTimes=$((${#shapingTimes[*]} / 3))

我发现这些变量返回了数组的各个方面,但没有返回键的总数

echo "All of the items in the array:" ${shapingTimes[*]}
echo "All of the indexes in the array:" ${!shapingTimes[*]}
echo "Total number of items in the array:" ${#shapingTimes[*]}
echo "Total number of KEYS in each array entry:" #???

所需的输出

All of the items in the array: 21 6 11 blah 15 4 bar 9 foo
All of the indexes in the array: 0-stop 1-stop 2-stop 2-anotherkey 0-start 1-start 1-anotherkey 2-start 0-anotherkey
Total number of items in the array: 9
Total number of KEYS in each array entry: 3

解决方法

declare -A shapingTimes
shapingTimes=([0-start]=15 [0-stop]=21 [0-anotherkey]=foo)
shapingTimes+=([1-start]=4  [1-stop]=6  [1-anotherkey]=bar)
shapingTimes+=([2-start]=9  [2-stop]=11 [2-anotherkey]=blah)

# output all keys
for i in "${!shapingTimes[@]}"; do echo $i; done

输出:

1-start
2-stop
1-stop
0-start
2-start
2-anotherkey
1-anotherkey
0-stop
0-anotherkey

# Leading numbers and "-" removed:
for i in "${!shapingTimes[@]}"; do echo ${i/#[0-9]*-/}; done

输出:

start
stop
stop
start
start
anotherkey
anotherkey
stop
anotherkey

# put shortend keys in new associative array
declare -A hash
for i in "${!shapingTimes[@]}"; do hash[${i/#[0-9]*-/}]=""; done
echo "${#hash[@]}"

输出:

3
,

一旦用-键入数组名称,就没有直接的方法来识别超过-字符的字符串的出现次数。

一种方法是使用其他工具来识别计数。 "${!shapingTimes[@]}"打印数组的所有键,sort -ut- k2根据-分隔符后面的2 nd 字段进行唯一排序,该字段通过管道传递到{ {1}}获取行数。

wc -l
,

@Cyrus's solution相同,但没有循环且没有子外壳:

#!/usr/bin/env bash

declare -A shapingTimes=(
  [0-start]=15 [0-stop]=21 [0-anotherkey]=foo
  [1-start]=4  [1-stop]=6  [1-anotherkey]=bar
  [2-start]=9  [2-stop]=11 [2-anotherkey]=blah
)

# Populate simple array with keys only
declare -a shapingTimesKeys=("${!shapingTimes[@]}")

# Create associative array entries declaration string
# populated by prefix stripped keys
printf -v _str '[%q]= ' "${shapingTimesKeys[@]/#[0-9]*-/}"

# Declare the stripped keys associative array using
# the string populated just above
declare -A shapingTimesHash="($_str)"

printf 'Found %d keys:\n' "${#shapingTimesHash[@]}"
printf '%q\n' "${!shapingTimesHash[@]}"