从CSV文件中提取符合特定条件的唯一GUID
需求说明
你手头有个4列的CSV文件(第4列大多为空),示例内容如下:
64fe12c7-b50c-4f63-b292-99f4ed74e5aa, ip, 1.2.3.4,
64fe12c7-b50c-4f63-b292-99f4ed74e5aa, ip, 4.5.6.7,
bacd8a9d-807f-4ae9-95d2-f7cc17222cab, ip, 0.0.0.0/0, silly string
bacd8a9d-807f-4ae9-95d2-f7cc17222cab, ip, 0.0.0.0/0, crazy town
db86d211-0b09-4a8f-b222-a21a54ad2f9c, ip, 8.9.0.1, wild wood
db86d211-0b09-4a8f-b222-a21a54ad2f9c, ip, 0.0.0.0/0, wacky tabacky
611f8cf5-f6f2-4f3a-ad24-12245652a7bd, ip, 0.0.0.0/0, cuckoo cachoo
需要筛选出满足以下三个条件的唯一GUID:
- 该GUID在文件中出现多次
- 对应行里至少有一行的第3列不是
0.0.0.0/0 - 对应行里至少有一行的第3列是
0.0.0.0/0
期望输出:
64fe12c7-b50c-4f63-b292-99f4ed74e5aa
db86d211-0b09-4a8f-b222-a21a54ad2f9c
解决方案:awk单行命令
用awk来处理这种按分组统计条件的场景最合适不过,直接用下面的命令就能搞定(假设你的文件名为data.csv):
awk -F, '{gsub(/^ +| +$/, "", $3); guid=$1; if ($3 == "0.0.0.0/0") has_zero[guid]=1; else has_nonzero[guid]=1; count[guid]++} END {for (g in count) if (count[g]>1 && has_zero[g] && has_nonzero[g]) print g}' data.csv
命令逻辑拆解
我给你一步步解释每个部分的作用,方便你理解和调整:
-F,:告诉awk用逗号作为CSV的字段分隔符gsub(/^ +| +$/, "", $3):清理第3列前后的空格——避免CSV里可能存在的空格导致匹配0.0.0.0/0时出错- 三个关联数组记录关键信息:
count[guid]:统计每个GUID出现的总次数has_zero[guid]:标记该GUID是否存在第3列为0.0.0.0/0的行has_nonzero[guid]:标记该GUID是否存在第3列不是0.0.0.0/0的行
END块:遍历所有统计过的GUID,只输出同时满足三个条件的GUID:出现次数>1、既有0.0.0.0/0的行、也有非0.0.0.0/0的行
测试结果
用你提供的示例数据运行这个命令,输出完全符合你的期望:
64fe12c7-b50c-4f63-b292-99f4ed74e5aa db86d211-0b09-4a8f-b222-a21a54ad2f9c
如果需要输出排序后的结果,只要在命令末尾加上| sort即可:
awk -F, '{gsub(/^ +| +$/, "", $3); guid=$1; if ($3 == "0.0.0.0/0") has_zero[guid]=1; else has_nonzero[guid]=1; count[guid]++} END {for (g in count) if (count[g]>1 && has_zero[g] && has_nonzero[g]) print g}' data.csv | sort
内容的提问来源于stack exchange,提问作者mikernova

