合并相同键的值

时间:2016-10-19 14:53:43

标签: linux bash shell awk

是否可以将awk用于同一个键的值到一行? 例如

a,100
b,200
a,131
a,102
b,203
b,301

我可以将它们转换为这样的文件:

a,100,131,102
b,200,203,301

4 个答案:

答案 0 :(得分:5)

您可以像这样使用awk:

awk -F, '{a[$1] = a[$1] FS $2} END{for (i in a) print i a[i]}' file

a,100,131,102
b,200,203,301

我们使用-F,将逗号用作分隔符,并使用数组a来保持聚合值。

参考: Effective AWK Programming

答案 1 :(得分:1)

如果Perl是一个选项,

perl -F, -lane '$a{$F[0]} = "$a{$F[0]},$F[1]"; END{for $k (sort keys %a){print "$k$a{$k}"}}' file

使用以下命令行选项:

  • -n循环输入文件的每一行
  • -l在处理之前删除换行符,然后将其添加回来
  • -a autosplit模式 - 将输入行拆分为@F数组。默认为在空格上拆分。
  • -e执行perl代码
  • -F autosplit修饰符,在这种情况下会在,
  • 上拆分

@F是每行中的单词数组,从$F[0]开始编制索引 $F[0]@F(关键)中的第一个元素 $F[1]@F(值)中的第二个元素 %a是一个哈希,它存储一个包含每个键的所有匹配项的字符串

答案 2 :(得分:0)

TL;博士

如果您预先输入输入,则可以使用sed来加入这些行,例如:

sort foo | sed -nE ':a; $p; N; s/^([^,]+)([^\n]+)\n\1/\1\2/; ta; P; s/.+\n//; ba'

更多解释

上述单行可以保存到脚本文件中。请参阅下面的注释版本。

parse.sed

# A goto label
:a

# Always print when on the last line
$p

# Read one more line into pattern space and join the
# two lines if the key fields are identical
N
s/^([^,]+)([^\n]+)\n\1/\1\2/

# Jump to label 'a' and redo the above commands if the
# substitution command was successful
ta

# Assuming sorted input, we have now collected all the
# fields for this key, print it and move on to the next
# key
P
s/.+\n//
ba

这里的逻辑如下:

  1. 假设已排序的输入。
  2. 看两个连续的行。如果它们的键字段匹配,则从第二行中删除该键并将值附加到第一行。
  3. 重复2.直到密钥匹配失败。
  4. 打印收集的值并重置以收集下一个键的值。
  5. 像这样运行:

    sort foo | sed -nEf parse.sed
    

    输出:

    a,100,102,131
    b,200,203,301
    

答案 3 :(得分:0)

使用datamash

$ datamash -st, -g1 collapse 2 <ip.txt
a,100,131,102
b,200,203,301

摘自手册:

  

-s,--sort

     

在分组之前对输入进行排序;这样就无需手动通过“ sort”通过管道传递输入

     

-t,--field-separator = X

     

使用X代替TAB作为字段分隔符

     

-g,--group = X [,Y,Z]

     

通过字段X,[Y,Z]

分组      

折叠

     

所有输入值的逗号分隔列表