Shell 用于对与名称关联的列求和的脚本
Shell script to sum columns associated with a name
我有一个文件,其中第 1 列有数千个数字,这些数字的每个序列都与一个人相关联。有人知道我如何创建一个 shell 脚本来为那个特定的人计算第 1 列的总和吗,例如:
John is 10+20+30+50 = 110
脚本的输出将是:John 110
依此类推..
我试过 while、for 等,但我无法将总和与人联系起来 :(
文件示例:
10 John
20 John
30 John
50 John
10 Paul
10 Paul
20 Paul
20 Paul
20 Robert
30 Robert
30 Robert
60 Robert
80 Robert
40 Robert
40 Robert
40 Robert
15 Mike
30 Mike
awk '{ map[]+= } END { for (i in map) { print i" "map[i] } }' file
使用 awk 创建一个数组,将名称作为第一个索引,每个名称的值总计 运行。最后,打印姓名和总数。
非常感谢 Raman,它成功了...您是否碰巧知道是否可以对同一个 awk 执行计算以获得每个计算的平均值?例如,约翰是 10+20+30+50 = 110, 110 / 4 = 27
假设:
- 数据位于名为
numbers.dat
的文件中
- 我们会将总数和计数存储在数组中,但计算平均值只是为了显示(OP 可以决定平均值是否也应该存储在数组中)
一个 bash
解决方案使用一对关联数组来跟踪我们的数字:
unset total count
declare -A total count
while read -r number name
do
(( total[${name}] += $number))
(( count[${name}] ++ ))
done < numbers.dat
typeset -p total count
这会生成:
declare -A total=([Mike]="45" [Robert]="340" [John]="110" [Paul]="60" )
declare -A count=([Mike]="2" [Robert]="8" [John]="4" [Paul]="4" )
如果我们想要基于整数的平均值(即没有小数位):
for i in ${!total[@]}
do
printf "%-10s %5d / %-5d = %5d\n" "${i}" "${total[${i}]}" "${count[${i}]}" $(( ${total[${i}]} / ${count[${i}]} ))
done
这会生成:
Mike 45 / 2 = 22
Robert 340 / 8 = 42
John 110 / 4 = 27
Paul 60 / 4 = 15
如果我们希望平均值包括 2 个小数位:
for i in ${!total[@]}
do
printf "%-10s %5d / %-5d = %5.2f\n" "${i}" "${total[${i}]}" "${count[${i}]}" $( bc <<< "scale=2;${total[${i}]} / ${count[${i}]}" )
done
这会生成:
Mike 45 / 2 = 22.50
Robert 340 / 8 = 42.50
John 110 / 4 = 27.50
Paul 60 / 4 = 15.00
按名称排序的输出:
for i in ${!total[@]}
do
printf "%-10s %5d / %-5d = %5.2f\n" "${i}" "${total[${i}]}" "${count[${i}]}" $( bc <<< "scale=2;${total[${i}]} / ${count[${i}]}" )
done | sort
这会生成:
John 110 / 4 = 27.50
Mike 45 / 2 = 22.50
Paul 60 / 4 = 15.00
Robert 340 / 8 = 42.50
一个 awk
解决方案,打印平均值到小数点后 2 位并按名称排序输出:
awk '
{ total[]+=
count[]++
}
END { PROCINFO["sorted_in"]="@ind_str_asc"
for ( i in total )
printf "%-10s %5d / %-5d = %5.2f\n", i, total[i], count[i], total[i]/count[i]
}
' numbers.dat
这会生成:
John 110 / 4 = 27.50
Mike 45 / 2 = 22.50
Paul 60 / 4 = 15.00
Robert 340 / 8 = 42.50
我有一个文件,其中第 1 列有数千个数字,这些数字的每个序列都与一个人相关联。有人知道我如何创建一个 shell 脚本来为那个特定的人计算第 1 列的总和吗,例如:
John is 10+20+30+50 = 110
脚本的输出将是:John 110
依此类推..
我试过 while、for 等,但我无法将总和与人联系起来 :(
文件示例:
10 John
20 John
30 John
50 John
10 Paul
10 Paul
20 Paul
20 Paul
20 Robert
30 Robert
30 Robert
60 Robert
80 Robert
40 Robert
40 Robert
40 Robert
15 Mike
30 Mike
awk '{ map[]+= } END { for (i in map) { print i" "map[i] } }' file
使用 awk 创建一个数组,将名称作为第一个索引,每个名称的值总计 运行。最后,打印姓名和总数。
非常感谢 Raman,它成功了...您是否碰巧知道是否可以对同一个 awk 执行计算以获得每个计算的平均值?例如,约翰是 10+20+30+50 = 110, 110 / 4 = 27
假设:
- 数据位于名为
numbers.dat
的文件中
- 我们会将总数和计数存储在数组中,但计算平均值只是为了显示(OP 可以决定平均值是否也应该存储在数组中)
一个 bash
解决方案使用一对关联数组来跟踪我们的数字:
unset total count
declare -A total count
while read -r number name
do
(( total[${name}] += $number))
(( count[${name}] ++ ))
done < numbers.dat
typeset -p total count
这会生成:
declare -A total=([Mike]="45" [Robert]="340" [John]="110" [Paul]="60" )
declare -A count=([Mike]="2" [Robert]="8" [John]="4" [Paul]="4" )
如果我们想要基于整数的平均值(即没有小数位):
for i in ${!total[@]}
do
printf "%-10s %5d / %-5d = %5d\n" "${i}" "${total[${i}]}" "${count[${i}]}" $(( ${total[${i}]} / ${count[${i}]} ))
done
这会生成:
Mike 45 / 2 = 22
Robert 340 / 8 = 42
John 110 / 4 = 27
Paul 60 / 4 = 15
如果我们希望平均值包括 2 个小数位:
for i in ${!total[@]}
do
printf "%-10s %5d / %-5d = %5.2f\n" "${i}" "${total[${i}]}" "${count[${i}]}" $( bc <<< "scale=2;${total[${i}]} / ${count[${i}]}" )
done
这会生成:
Mike 45 / 2 = 22.50
Robert 340 / 8 = 42.50
John 110 / 4 = 27.50
Paul 60 / 4 = 15.00
按名称排序的输出:
for i in ${!total[@]}
do
printf "%-10s %5d / %-5d = %5.2f\n" "${i}" "${total[${i}]}" "${count[${i}]}" $( bc <<< "scale=2;${total[${i}]} / ${count[${i}]}" )
done | sort
这会生成:
John 110 / 4 = 27.50
Mike 45 / 2 = 22.50
Paul 60 / 4 = 15.00
Robert 340 / 8 = 42.50
一个 awk
解决方案,打印平均值到小数点后 2 位并按名称排序输出:
awk '
{ total[]+=
count[]++
}
END { PROCINFO["sorted_in"]="@ind_str_asc"
for ( i in total )
printf "%-10s %5d / %-5d = %5.2f\n", i, total[i], count[i], total[i]/count[i]
}
' numbers.dat
这会生成:
John 110 / 4 = 27.50
Mike 45 / 2 = 22.50
Paul 60 / 4 = 15.00
Robert 340 / 8 = 42.50