【问题标题】:how to sum each column in a file using bash如何使用bash对文件中的每一列求和
【发布时间】:2013-02-19 11:23:47
【问题描述】:

我有一个格式如下的文件

id_1,1,0,2,3,lable1
id_2,3,2,2,1,lable1
id_3,5,1,7,6,lable1

我想要每一列的总和(我有超过 300 列)

9,3,11,10,lable1 

我怎样才能使用 bash 做到这一点。 我尝试使用here 描述的内容,但没有奏效。

【问题讨论】:

    标签: bash shell awk


    【解决方案1】:

    使用awk

    $ awk -F, '{for (i=2;i<NF;i++)a[i]+=$i}END{for (i=2;i<NF;i++) printf a[i]",";print $NF}' file
    9,3,11,10,lable1
    

    这将在逗号分隔的文件中打印每列的总和(来自 i=2 .. i=n-1),然后是最后一行的最后一列的值 (即标签1)

    【讨论】:

      【解决方案2】:

      如果需要按最后一列中的标签对总计进行分组,您可以试试这个:

      awk -F, '
        {
          L[$NF]
          for(i=2; i<NF; i++) T[$NF,i]+=$i
        }
        END{
          for(i in L){
            s=i
            for(j=NF-1; j>1; j--) s=T[i,j] FS s
            print s
          }
        }
      ' file
      

      如果最后一列中的标签已排序,那么您可以尝试不使用数组并节省内存:

      awk -F, '
        function labelsum(){
          s=p
          for(i=NF-1; i>1; i--) s=T[i] FS s
          print s
          split(x,T)
        }
        p!=$NF{
          if(p) labelsum()
          p=$NF
        }
        {
          for(i=2; i<NF; i++) T[i]+=$i
        }
        END {
          labelsum()
        }
      ' file
      

      【讨论】:

      • 感谢您的解决方案增加了在文件中使用多个标签的优势
      【解决方案3】:

      这是一个 Perl 单行代码:

      <file perl -lanF, -E 'for ( 0 .. $#F ) { $sums{ $_ } += $F[ $_ ]; } END { say join ",", map { $sums{ $_ } } sort keys %sums; }'
      

      它只会求和,因此示例中的第一列和最后一列将为 0。

      此版本将遵循您的示例输出:

      <file perl -lanF, -E 'for ( 1 .. $#F - 1 ) { $sums{ $_ } += $F[ $_ ]; } END { $sums{ $#F } = $F[ -1 ]; say join ",", map { $sums{ $_ } } sort keys %sums; }'
      

      【讨论】:

        【解决方案4】:

        基于您链接的解决方案的修改版本:

        #!/bin/bash
        
        colnum=6
        filename="temp"
        
        for ((i=2;i<$colnum;++i))
        do
          sum=$(cut -d ',' -f $i $filename | paste -sd+ | bc)
          echo -n $sum','
        done
        head -1 $filename | cut -d ',' -f $colnum
        

        【讨论】:

          【解决方案5】:

          纯 bash 解决方案:

          #!/usr/bin/bash
          
          
          while IFS=, read -a arr
          do
                  for((i=1;i<${#arr[*]}-1;i++))
                  do
                          ((farr[$i]=${farr[$i]}+${arr[$i]}))
                  done
                  farr[$i]=${arr[$i]}
          done < file
          (IFS=,;echo "${farr[*]}")
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-24
            • 1970-01-01
            • 1970-01-01
            • 2021-11-23
            • 2015-05-19
            • 1970-01-01
            相关资源
            最近更新 更多