如何通过仅匹配每一行的一部分而不是整行本身来找到重复的行?
以下面的文字为例:
uid=154163(j154163) gid=10003(pemcln) groups=10003(pemcln) j154163
uid=152084(k152084) gid=10003(pemcln) groups=10003(pemcln) k152084
uid=154163(b153999) gid=10003(pemcln) groups=10003(pemcln) b153999
uid=154226(u154226) gid=10003(pemcln) groups=10003(pemcln) u154226
我只想显示第1行和第3行,因为它们具有相同的重复UID值“154163”
我知道的唯一方法是如何匹配整条线而不是每条线的子集。
答案 0 :(得分:1)
此代码查找每行的ID。如果任何ID出现多次,则会打印其行:
$ awk -F'[=(]' '{cnt[$2]++;lines[$2]=lines[$2]"\n"$0} END{for (k in cnt){if (cnt[k]>1)print lines[k]}}' file
uid=154163(j154163) gid=10003(pemcln) groups=10003(pemcln) j154163
uid=154163(b153999) gid=10003(pemcln) groups=10003(pemcln) b153999
-F'[=(]'
awk
将输入文件分隔为记录(行)并将记录分隔为字段。在此,我们告诉awk
使用=
或(
作为字段分隔符。这样做是为了使第二个字段是ID。
cnt[$2]++; lines[$2]=lines[$2]"\n"$0
对于每个读入的行,我们会计算ID出现次数的计数cnt
。此外,我们会在数组lines
中保存与该ID相关联的所有行。
END{for (k in cnt){if (cnt[k]>1)print lines[k]}}
在我们到达文件末尾后,我们会查看每个观察到的ID,如果它出现不止一次,则会打印出它的行。
答案 1 :(得分:0)
有人已经提供了一个awk
脚本,可以满足您的需要,假设文件足够小以适应内存(它们存储所有行直到结束然后决定什么输出)。它没有任何问题,实际上它可以被认为是这个问题的规范awk
解决方案。我真的为awk
可能会遇到存储要求的情况提供了这个答案。
具体来说,如果您有较大的文件导致该方法出现问题,以下awk
脚本myawkscript.awk
将处理它,前提是您首先对文件进行排序,以便它可以依赖于相关事实线条在一起。为了确保它已排序并且您可以轻松获取相关键(使用=
和(
作为字段分隔符),您可以使用以下命令调用它:
sort <inputfile | awk -F'[=(]' -f myawkscript.awk
脚本是:
state == 0 {
if (lastkey == $2) {
printf "%s", lastrec;
print;
state = 1;
};
lastkey = $2;
lastrec = $0"\n";
next;
}
state == 1 {
if (lastkey == $2) {
print;
} else {
lastkey = $2;
lastrec = $0"\n";
state = 0;
}
}
它基本上是一个状态机,其中状态零扫描重复项,状态一是输出重复项。
在状态0中,当前行的相关部分将与前一行进行检查,如果匹配,则输出两者并切换到状态1。如果没有匹配,它只是移动到下一行。
在状态一中,它会检查每一行与原始集合中的原始行,并在匹配时输出。当它找到一个不匹配的时,它会存储它并恢复到状态零。