【问题标题】:awk: enumerate fields based on another common fieldawk:基于另一个公共字段枚举字段
【发布时间】:2021-06-19 00:49:35
【问题描述】:

这很可能是用数组完成的,但我不知道如何构建逻辑。

输入:

uid1 ip1 tag1
uid1 ip1 tag2
uid2 ip2 tag3
uid2 ip2 tag4
uid2 ip2 tag5

期望的输出:

uid1 ip1 tag1,tag2
uid2 ip2 tag3,tag4,tag5

我在想,也许这可以通过将所有元素存储在array1 中,然后将uid + ip 字段存储在array2 中,然后通过迭代来自array2 的元素来搜索array1

【问题讨论】:

    标签: arrays awk


    【解决方案1】:
    awk -v OFS=, '{
             k=$1 SUBSEP $2; 
             arr[k] = k in arr ? arr[k] OFS $3 : $0;
          }
          END{
             for(i in arr)
                print arr[i]
          }' infile
    

    测试结果:

    $ cat f1
    uid1 ip1 tag1
    uid1 ip1 tag2
    uid2 ip2 tag3
    uid2 ip2 tag4
    uid2 ip2 tag5
    
    $ awk -v OFS=, '{k=$1 SUBSEP $2; arr[k] = k in arr ? arr[k] OFS $3 : $0;}END{for(i in arr)print arr[i]}' f1
    uid1 ip1 tag1,tag2
    uid2 ip2 tag3,tag4,tag5
    

    说明:

    awk -v OFS=, '{                                   # output field separator
             # variable k contains field1 value 
             # and  SUBSEP - Multi-dimensional array separator 
             # and column 2 value
    
             k=$1 SUBSEP $2; 
    
             # arr -> array
             # if array key that is variable k already exists in array arr
             # then arr[k] will be existing content of arr[k]  plus
             # field separator (comma) and then field 3 contents
             # else entire row/record which is when array does not have index already
    
             arr[k] = k in arr ? arr[k] OFS $3 : $0;
    
          }
          END{                      # END block
    
             # iterate through array arr
             # and print array value
    
             for(i in arr)
                print arr[i]
    
          }' infile
    

    下面的三元运算符

    arr[k] = k in arr ? arr[k] OFS $3 : $0;
    

    if(k in arr){
      arr[k] = arr[k] OFS $3
    }else{
      arr[k] = $0
    }
    

    【讨论】:

    • 谢谢,它按预期工作。我不能说我可以破译整个代码,所以我可以更好地理解它是如何工作的。具体来说,这些部分:k=$1 SUBSEP $2arr[k] = k in arr ? arr[k] OFS $3 : $0
    • @one-liner 补充说明
    • @Akshay,感谢您分享精彩的答案。
    • 真的很好解释
    【解决方案2】:

    GNU datamash

    $ datamash -W -t' ' -g1,2 collapse 3 <ip.txt
    uid1 ip1 tag1,tag2
    uid2 ip2 tag3,tag4,tag5
    
    • -W 使用空格/制表符作为输入字段分隔符
    • -t' ' 空格作为输出字段分隔符
    • -g1,2 基于字段 12 的组
    • collapse 3 对字段 3 执行的操作

    【讨论】:

    • 我不知道datamash,语法看起来更简单更干净,不幸的是它默认没有安装在我的目标环境中。不过会记住这一点,以备将来使用。
    猜你喜欢
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 2017-07-12
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 2021-09-18
    相关资源
    最近更新 更多