我尝试在 bash-4.1
下解析这样的多个文件$cat hostname_abc.txt
host_type type_foo
SoftA version123
SoftB version456
获取输出,您可以看到使用Soft [A,B]版本的次数,按主机类型分组:
$./list_versions.sh
[type_foo] 11 times
SoftA:
[version123] 1 times
[version444] 5 times
[version567] 5 times
SoftB:
[version456] 9 times
[version777] 2 times
[type_bar] 6 times
SoftA:
[version444] 6 times
SoftB:
[version111] 4 times
[version777] 2 times
我事先并不知道host_type和版本的列表。 因此,我尝试在关联数组中保存每个host_type的计数,并创建动态关联数组的名称,这些数据存储基于每个host_type的每个版本的Soft [A,B]的计数。模板host_type_Soft [A,B]
我尝试了多次语法和间接的不同变化,所以我重新编写了一个更符合我目标的可读脚本:
#!/usr/bin/env bash
# ----- generated test conditions -----
echo -e "host_type typeA\nSoftA v2\nSoftB v1" > hostname_1.txt
echo -e "host_type typeB\nSoftA v1\nSoftB v1" > hostname_2.txt
echo -e "host_type typeB\nSoftA v1\nSoftB v0" > hostname_3.txt
echo -e "host_type typeA\nSoftA v0\nSoftB v0" > hostname_4.txt
echo -e "host_type typeA\nSoftA v3\nSoftB v2" > hostname_5.txt
echo -e "host_type typeB\nSoftA v3\nSoftB v1" > hostname_6.txt
echo -e "host_type typeB\nSoftA v2\nSoftB v2" > hostname_7.txt
echo -e "host_type typeA\nSoftA v1\nSoftB v2" > hostname_8.txt
echo -e "host_type typeC\nSoftA v0\nSoftB v4" > hostname_9.txt
list_hostname() {
for i in {1..9}; do
echo "hostname_${i}.txt"
done
}
declare -A list_host_type
while read f; do
#parse the hostname files
while read l; do
[[ $l = *"host_type"* ]] && host_type="$( echo $l | cut -d' ' -f2)"
[[ $l = *"SoftA"* ]] && versionA="$( echo $l | cut -d' ' -f2)"
[[ $l = *"SoftB"* ]] && versionB="$( echo $l | cut -d' ' -f2)"
done < <( cat "$f" )
#count the number of hosts by host_type
[[ ${list_host_type[$host_type]} ]] && ((list_host_type[$host_type]++)) || list_host_type[$host_type]='1'
#create associative arrays with a name only know at runtime
declare -A "${host_type}_SoftA"
declare -A "${host_type}_SoftB"
#count the number of host for the couple host_type and Soft[A,B], stored on the dynamically named assiociative array
[[ ${${host_type}_SoftA[$versionA]} ]] && ((${host_type}_SoftA[$versionA]++)) || ${host_type}_SoftA[$versionA]='1'
[[ ${${host_type}_SoftB[$versionB]} ]] && ((${host_type}_SoftB[$versionB]++)) || ${host_type}_SoftB[$versionB]='1'
done < <( list_hostname )
#print a non pretty-formated output
echo '==== result ====='
for m in "${!list_host_type[@]}"; do
echo "host type: $m count: ${list_model[$m]}"
for versionA in "${!${m}_softA[@]}"; do
echo " SoftA version: $versionA count: ${${m}_SoftA[$versionA]}"
done
for versionB in "${!${m}_softB[@]}"; do
echo " SoftB version: $versionB count: ${${m}_SoftB[$versionB]}"
done
done
我知道他们是实现我的目标的其他方法,但我想知道我是否可以通过bash-4.1
这种方式使用关联。
答案 0 :(得分:1)
我认为你不能在Bash中使用带有数组的动态变量名。 (我尝试了一些但无法弄清楚语法。) 即使可能,我认为理解起来非常困难。
可能的解决方法可能是使用单个关联数组, 用“复合键”。 也就是说,例如使用逗号分隔的主机类型值,soft和version:
while read f; do
line=0
while read col1 col2; do
if [[ $line = 0 ]]; then
host_type=$col2
else
soft=$col1
version=$col2
index=$host_type,$soft,$version
((list_host_type[$index]++))
fi
((line++))
done < <( cat "$f" )
done < <( list_hostname )
for m in "${!list_host_type[@]}"; do
echo $m = ${list_host_type[$m]}
done
对于您的样本数据,这将产生:
typeA,SoftA,v2 = 1 typeA,SoftA,v3 = 1 typeA,SoftA,v0 = 1 typeA,SoftA,v1 = 1 typeB,SoftA,v3 = 1 typeB,SoftA,v2 = 1 typeB,SoftA,v1 = 2 typeA,SoftB,v2 = 2 typeA,SoftB,v1 = 1 typeA,SoftB,v0 = 1 typeC,SoftB,v4 = 1 typeB,SoftB,v2 = 1 typeB,SoftB,v0 = 1 typeB,SoftB,v1 = 2 typeC,SoftA,v0 = 1
然后使用此关联数组来计算所需的统计信息。这是一个粗略的示例实现:
get_host_types() {
local names=(${!list_host_type[@]})
printf "%s\n" "${names[@]%%,*}" | sort -u
}
get_soft() {
local host_type=$1
local names=(${!list_host_type[@]})
for name in "${names[@]}"; do
[[ ${name%%,*} = $host_type ]] && echo $name
done | cut -d, -f2 | sort -u
}
get_versions() {
local prefix=$1
local names=(${!list_host_type[@]})
for name in "${names[@]}"; do
[[ ${name%,*} = $prefix ]] && echo $name
done | cut -d, -f3 | sort -u
}
indent=" "
for host_type in $(get_host_types); do
echo "[$host_type]"
for soft in $(get_soft $host_type); do
echo "$indent$soft:"
for version in $(get_versions $host_type,$soft); do
index=$host_type,$soft,$version
echo "$indent$indent[$version] ${list_host_type[$index]} times"
done
done
done
作为输出产生:
[typeA] SoftA: [v0] 1 times [v1] 1 times [v2] 1 times [v3] 1 times SoftB: [v0] 1 times [v1] 1 times [v2] 2 times [typeB] SoftA: [v1] 2 times [v2] 1 times [v3] 1 times SoftB: [v0] 1 times [v1] 2 times [v2] 1 times [typeC] SoftA: [v0] 1 times SoftB: [v4] 1 times
总而言之,使用适当的编程语言实现它会更好。