【问题标题】:Shell script to sum columns associated with a name用于汇总与名称关联的列的 Shell 脚本
【发布时间】:2021-05-02 10:24:44
【问题描述】:

我在第 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

【问题讨论】:

  • 请用您的附加要求(例如,平均)和预期输出更新问题

标签: bash shell sum ksh


【解决方案1】:

一个awk 解决方案,将平均值打印到小数点后 2 位并按名称排序输出:

awk '
    { total[$2]+=$1
      count[$2]++
    }
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

【讨论】:

    【解决方案2】:
    awk '{ map[$2]+=$1 } END { for (i in map) { print i" "map[i] } }' file
    

    使用 awk,创建一个数组,其中名称作为第一个索引,每个名称的值的总和。最后,打印姓名和总数。

    【讨论】:

      【解决方案3】:

      非常感谢拉曼,它起作用了...您是否碰巧知道是否可以对同一个 awk 执行计算以获得每个 awk 的平均值?例如,约翰是 10+20+30+50 = 110, 110 / 4 = 27

      【讨论】:

        【解决方案4】:

        假设:

        • 数据位于名为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
        

        【讨论】:

          猜你喜欢
          • 2013-07-29
          • 2019-06-23
          • 2011-11-03
          • 1970-01-01
          • 2014-03-09
          • 2010-10-15
          • 1970-01-01
          • 1970-01-01
          • 2023-04-06
          相关资源
          最近更新 更多