如何按列删除重复项(反向排序)

时间:2014-08-18 13:03:12

标签: bash sorting sed

我在这里寻找这个,但没有找到确切的情况。对不起,如果它是重复的,但我找不到它。

我在Debian中有一个巨大的文件,其中包含由"#"分隔的4列,格式如下:

username#source#date#time

例如:

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-07#14:31:40
A222222#Juniper#2014-08-08#09:15:34
A111111#Juniper#2014-08-10#14:32:55
A111111#Windows#2014-08-08#10:27:30

我想根据前两列打印唯一行,如果找到重复行,则必须根据日期/时间打印最后一个事件。使用上面的列表,结果应为:

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-08#09:15:34
A111111#Juniper#2014-08-10#14:32:55
A111111#Windows#2014-08-08#10:27:30

我使用两个命令对其进行了测试:

cat file | sort -u -t# -k1,2
cat file | sort -r -u -t# -k1,2

但他们两个都打印出以下内容:

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-07#14:31:40 --> Wrong line, it is older than the duplicate one
A111111#Juniper#2014-08-10#14:32:55
A111111#Windows#2014-08-08#10:27:30

有什么办法吗?

谢谢!

4 个答案:

答案 0 :(得分:3)

这应该有效

tac file | awk -F# '!a[$1,$2]++' | tac

输出

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-08#09:15:34
A111111#Juniper#2014-08-10#14:32:55
A111111#Windows#2014-08-08#10:27:30

答案 1 :(得分:2)

awk -F\# '{ p = ($1 FS $2 in a ); a[$1 FS $2] = $0 }
          !p { keys[++k] = $1 FS $2 }
          END { for (k = 1; k in keys; ++k) print a[keys[k]] }' file

输出:

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-08#09:15:34
A111111#Juniper#2014-08-10#14:32:55
A111111#Windows#2014-08-08#10:27:30

答案 2 :(得分:2)

首先,您需要对输入文件进行排序以确保行的顺序,例如对于重复的用户名#来源,您将获得订购时间。最好是反过来,所以最后一个事件是第一个。这可以通过简单的排序来完成,例如:

sort -r < yourfile

这将从您的输入产生下一个:

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-08#09:15:34
A222222#Juniper#2014-08-07#14:31:40
A111111#Windows#2014-08-08#10:27:30
A111111#Juniper#2014-08-10#14:32:55

反向排序的行,其中对于每个username#source组合,最新事件首先出现。

接下来,您需要对排序的行进行一些过滤,以便仅获取第一个事件。这可以使用多个工具完成,例如awkuniqperl等等,

所以,解决方案

 sort -r <yourfile | uniq -w16

sort -r <yourfile | awk -F# '!seen[$1,$2]++'

sort -r yourfile | perl -F'#' -lanE  'say $_ unless $seen{"$F[0],$F[1]"}++'

以上所有内容将打印下一个

A222222#Windows#2014-08-18#10:47:16
A222222#Juniper#2014-08-08#09:15:34
A111111#Windows#2014-08-08#10:27:30
A111111#Juniper#2014-08-10#14:32:55

最后,您可以根据需要重新排序唯一的行。

答案 3 :(得分:0)

如果你知道第一列总是7个字符长,第二列也是7个字符长,你可以提取唯一的行,只考虑前16个字符:

uniq file -w 16

由于您希望后者重复,您可以在tac之前使用uniq反转数据,然后再次反转输出:

tac file | uniq -w 16 | tac

更新:如下所示,uniq需要对行进行排序。在这种情况下,这开始变得做作,基于awk的建议更好。这样的事情仍然有效:

sort -s -t"#" -k1,2 file | tac | uniq -w 16 | tac