显示包含字符串子集内重复项的行

时间:2015-01-06 00:41:13

标签: string bash duplicates

如何通过仅匹配每一行的一部分而不是整行本身来找到重复的行?

以下面的文字为例:

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”

我知道的唯一方法是如何匹配整条线而不是每条线的子集。

2 个答案:

答案 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。如果没有匹配,它只是移动到下一行。

在状态一中,它会检查每一行与原始集合中的原始行,并在匹配时输出。当它找到一个不匹配的时,它会存储它并恢复到状态零。