如果第二列中的数据相同,则按第一列添加Bash

时间:2017-11-14 14:34:11

标签: linux bash shell awk sed

我有一个包含分隔符的列表|

40|192.168.1.2|user4
42|192.168.1.25|user2
58|192.168.1.55|user3
118|192.168.1.3|user11
67|192.168.1.25|user2

如您所见,我在字段42|192.168.1.25|user2和字段67|192.168.1.25|user2中拥有相同的IP。我怎样才能在它们之间添加这些线?你能用awk给我一个解决方案吗?你能给我一些例子吗?

我需要一个像这样的结果:

40|192.168.1.2|user4
58|192.168.1.55|user3
109|192.168.1.25|user2
118|192.168.1.3|user11

你怎么看,我们已经计算了第一栏的数字。

5 个答案:

答案 0 :(得分:1)

如果您需要输出与Input_file相同的顺序,那么关注awk可能对您有帮助。

awk -F"|" '!c[$2,$3]++{val++;v[val]=$2$3} {a[$2,$3]+=$1;b[$2,$3]=$2 FS $3;} END{for(j=1;j<=val;j++){print a[v[j]] FS b[v[j]]}}' SUBSEP=""   Input_file

现在也添加非单线形式的解决方案。

awk -F"|" '        ##Making field separator as pipe(|) here for all the lines for Input_file.
!c[$2,$3]++{       ##Checking if array C whose index is $2,$3 is having its first occurrence in array c then do following.
  val++;           ##incrementing variable val value with 1 each time cursor comes here.
  v[val]=$2$3      ##creating an array named v whose index is val and value is $2$3(second field 3rd field).
}                  ##Closing c array block here now.
{
  a[$2,$3]+=$1;    ##creating an array named a whose index is $2 $3 and incrementing its value with 1st field value and add in its same index values to get SUM.
  b[$2,$3]=$2 FS $3;##create array b with index of $2$3 and setting its value to $2 FS $3, where FS is field separator.
}                  ##closing this block here.
END{               ##Starting awk code END bock here.
  for(j=1;j<=val;j++){ ##starting a for loop here from variable named j value 1 to till value of variable val here.
    print a[v[j]] FS b[v[j]] ##printing value of array a whose index is value of array v with index j, and array b with index of array v with index j here.
}}
' SUBSEP="" Input_file       ##Setting SUBSEP to NULL here and mentioning the Input_file name here.

答案 1 :(得分:1)

短GNU datamash + awk 解决方案:

datamash -st'|' -g2,3 sum 1 <file | awk -F'|' '{print $3,$1,$2}' OFS='|'
  • g2,3 - 按第2和第3个字段分组(即 IP地址用户ID

  • sum 1 - 对分组记录中的第一个字段值求和

输出:

40|192.168.1.2|user4
109|192.168.1.25|user2
118|192.168.1.3|user11
58|192.168.1.55|user3

答案 2 :(得分:1)

修改示例数据以包含ip地址192.168.1.25的不同用户:

$ cat ipfile
40|192.168.1.2|user4
42|192.168.1.25|user1      <=== same ip, different user
58|192.168.1.55|user3
118|192.168.1.3|user11
67|192.168.1.25|user9      <=== same ip, different user

一个简单的awk脚本:

$ awk '
BEGIN { FS="|" ; OFS="|" }
{ sum[$2]+=$1 ; if (user[$2]=="") { user[$2]=$3 } }
END { for (idx in sum) { print sum[idx],idx,user[idx] } }
' ipfile

58|192.168.1.55|user3
40|192.168.1.2|user4
118|192.168.1.3|user11
109|192.168.1.25|user1     <=== captured first user id
  • BEGIN { FS="|" ; OFS="|" }:定义输入和输出字段分隔符;在开始时执行一次
  • sum[$2]+=$1:将字段#1存储/添加到数组(由ip address == field#2索引);对数据文件中的每一行执行一次
  • if ....:如果用户尚未针对给定的IP地址存储,则立即存储;这样可以保存我们为给定IP地址找到的第一个用户ID;对数据文件中的每一行执行一次
  • END { for .... / print ...}:遍历数组索引,打印sum,ip地址和(第一个)用户ID;最后执行一次

注意:原始问题没有提供分类要求;可以根据需要添加排序......

答案 3 :(得分:1)

awk救援!

$ awk 'BEGIN {FS=OFS="|"} 
             {a[$2 FS $3]+=$1} 
       END   {for(k in a) print a[k],k}' file | sort -n

40|192.168.1.2|user4
58|192.168.1.55|user3
109|192.168.1.25|user2
118|192.168.1.3|user11

如果用户*不是密钥的一部分,并且您想要捕获第一个值

$ awk 'BEGIN {FS=OFS="|"} 
             {c[$2]+=$1; 
              if(!($2 in u)) u[$2]=$3}     # capture first user
       END   {for(k in c) print c[k],k,u[k]}' file | sort -n

最终与@ markp的答案几乎相同。

答案 4 :(得分:1)

同一路径上的另一个想法,但允许不同的用户:

awk -F'|' '{c[$2] += $1}u[$2] !~ $3{u[$2] = (u[$2]?u[$2]",":"")$3}END{for(i in c)print c[i],i,u[i]}' OFS='|' input_file

如果有多个用户,他们将用逗号分隔