Bash - 根据列添加行中的值

时间:2015-04-01 07:57:10

标签: bash csv awk sed command-line-interface

我的csv文件中的第二列有重复项。我想根据这些重复项添加第1列中的关联值。

示例csv:

56,  cc=DK
49,  cc=US
34,  cc=GB
32,  cc=DE
32,  cc=NZ
31,  cc=DK
31,  cc=GB
31,  cc=GB

示例结果:

96,  cc=GB # where 96 = 34+31+31
87,  cc=DK # where 87 = 56+31
32,  cc=DE
32,  cc=NZ

3 个答案:

答案 0 :(得分:2)

您可以在awk中使用关联数组:

awk '{s[$2]+=$1}END{for(k in s)print s[k]", ",k}' inFile

为了便于阅读而扩展,并使用sum/key而不是s/k

{                                 # Do for each line.
    sum[$2] += $1                 # Add first field to accumulator,
                                  #   indexed by second field.
                                  #   initial value is zero.
}
END {                             # Do this bit when whole file processed.
    for (key in sum)              # For each key like cc=US:
        print sum[key] ", " key   # Output the sum and key.
}

这是我的盒子上的示例:

pax$ echo;echo '56,  cc=DK
49,  cc=US
34,  cc=GB
32,  cc=DE
32,  cc=NZ
31,  cc=DK
31,  cc=GB
31,  cc=GB' | awk '{s[$2]+=$1}END{for(k in s)print s[k]", "k}'

32, cc=DE
96, cc=GB
32, cc=NZ
49, cc=US
87, cc=DK

尽管第一列的格式为999,(注意末尾的逗号),但这只是因为awk在评估数字上下文中的字符串时仅使用前缀这在上下文中是有效的。因此45xyzzy将变为45,更重要的是49,变为49

答案 1 :(得分:1)

Perl解决方案:

perl -ane '$h{ $F[1] } += $F[0] }{ print "$h{$_}\t$_\n" for keys %h' input.csv

说明:

  • -n逐行处理输入行
  • -a将空格上的输入行拆分为@F数组
  • 中的字段
  • 哈希表%h记录每个键的总和(2 nd 列)。它只是将第一列的值添加到它。
  • }{(称为" Eskimo greeting")将每行(-n)执行的内容与处理完整输入后要运行的代码分开/ LI>

答案 2 :(得分:0)

使用awk来完成这么简单的任务是可以的,但是如果你有很多类似的任务,而且将来可能需要更改它,那么很容易搞砸了。

由于它是典型的数据库问题,请考虑使用sqlite

你可以:

  1. 添加行名并删除多余的空格:

    $ cat <(echo "num, name") originalInput.txt | tr -d ' ' > input.csv
    
  2. 将数据导入临时sqlite db:

    $ sqlite3 --batch temp.db <<EOF!
    .mode csv
    .import input.csv input
    EOF!
    
  3. 从db:

    中选择
    $sqlite3 temp.db 'SELECT sum(num), name FROM input GROUP BY name'
    32|cc=DE
    87|cc=DK
    96|cc=GB
    32|cc=NZ
    49|cc=US
    
  4. 稍微多一些代码并使用外部sqlite3命令,但它显着不易出错,更强灵活。您可以轻松地连接多个csv文件,使用花式排序等。

    另外,想象一下你自己在六个月后查看代码,试图快速了解它的作用。