awk:基于另一个公共字段枚举字段
Posted
技术标签:
【中文标题】awk:基于另一个公共字段枚举字段【英文标题】:awk: enumerate fields based on another common field 【发布时间】: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
。
【问题讨论】:
【参考方案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;ENDfor(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 $2
和 arr[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
基于字段 1
和 2
的组
collapse 3
对字段 3
执行的操作
【讨论】:
我不知道datamash
,语法看起来更简单更干净,不幸的是它默认没有安装在我的目标环境中。不过会记住这一点,以备将来使用。以上是关于awk:基于另一个公共字段枚举字段的主要内容,如果未能解决你的问题,请参考以下文章