Linux汇总表并汇总每个给定事件的所有列

时间:2018-10-25 17:32:56

标签: shell awk grep summary

完成分析后,我得到了一个包含许多列和行的表。另外,随着新表的写入,行/列的数量可能会有所不同,因此我无法预测每行将有多少行。每行在第一列中都有一个索引,但是这些索引可以在表中重复。所以我想要的是一种grep / awk / bash方式,以相同的索引检索所有这些行,并对所有列求和,以得到总和仅为一行。 作为说明:

index,sampleA,sampleB,sampleC
nana,22,12,4
baba,47,4,5
nana,1,5,9
nana,7,5,8

解析后

index,sampleA,sampleB,sampleC
nana,30,22,21
baba,47,4,5

如果您能帮助我,我将非常感激。 非常感谢。

2 个答案:

答案 0 :(得分:0)

有点long,但是这样的事情会做:

awk -F"," 'BEGIN{OFS=FS} NR==1{print $0; next} NR>1{sampleA[$1]+=$2; sampleB[$1]+=$3; sampleC[$1]+=$4}END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}' yourfile

说明:

  1. 用逗号-F","分隔每行
  2. 在处理文件之前,请确保输出字段分隔符与字段分隔符(逗号)BEGIN{OFS=FS}
  3. 相匹配
  4. 如果这是文件的第一行,则将其打印出来(它是标题),然后继续到下一行NR==1{print $0; next}
  5. 如果这不是标题行,则创建三个数组来存储第2、3、4列中的累积值。这些数组的“键”是第1列NR>1{sampleA[$1]+=$2; sampleB[$1]+=$3; sampleC[$1]+=$4}中的值
  6. 最后,循环遍历三个数组中的第一个(它们的长度都相同,因此我们只需要循环一个)。然后打印出存储在每个密钥中的值:END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}

答案 1 :(得分:0)

您没有指定外壳,但是如果您喜欢使用ksh(93l +),那也可以解决问题。

尽管如此,该脚本还是有一些假设:

  1. 可以有任意数量的列,但每行具有相同的列数
  2. 索引名称中没有空格
  3. 每一列总是有一个值

    #!/bin/ksh
    
    # CSV to input as first argument, CSV to ouput as second argument
    InputCSV=$1
    OutputCSV=$2
    
    typeset -A Index
    
    while read line; do
        lineArray=(${line//,/ })
        # Assume that the first column is always named "index", but you can modify this
        if [[ ${lineArray[0]} == "index" ]]; then
            titleArray=(${line//,/ })
            continue
        fi
        for ((i=1;i<${#lineArray[*]};i++)); do
            if [[ -z ${Index[${lineArray[0]}][${titleArray[$i]}]} ]]; then
                    Index[${lineArray[0]}]+=( [${titleArray[$i]}]=${lineArray[$i]} )
            else
                    Index[${lineArray[0]}][${titleArray[$i]}]=$(( ${Index[${lineArray[0]}][${titleArray[$i]}]} + ${lineArray[$i]} ))
            fi
        done
    done < $InputCSV
    
    exec 3>$OutputCSV
    
    titleBar=${titleArray[0]}
    for ((i=1;i<${#titleArray[*]};i++)); do
        titleBar+=",${titleArray[$i]}"
    done
    
    print $titleBar >&3
    
    for j in ${!Index[@]}; do
        outLine=$j
        for ((i=1;i<${#titleArray[*]};i++)); do
                outLine+=",${Index[$j][${titleArray[$i]}]}"
        done
        print $outLine >&3
    done
    
    exec 3>&-