Bash - 根据列在行中添加值

Bash - adding values in row based on column

我的 csv 文件中的第 2 列有重复项。我想根据这些重复项添加第 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

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

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

为了可读性对其进行扩展,并使用 sum/key 而不是 s/k:

{                                 # Do for each line.
    sum[] +=                  # 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[]+=}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.

Perl 解决方案:

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

解释:

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

使用 awk 完成如此简单的任务没问题,但如果您有一堆类似的任务并且您将来可能需要更改它,那么很容易搞砸。

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

您可以:

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

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

    $ sqlite3 --batch temp.db <<EOF!
    .mode csv
    .import input.csv input
    EOF!
    
  3. select 来自数据库:

    $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
    

它的代码稍微多一点,并使用外部 sqlite3 命令,但它显着 不易出错 并且更 灵活 .您可以轻松加入多个 csv 文件、使用花式排序等。

此外,想象一下您六个月后查看代码并试图快速理解它的作用。