删除重复的行并扭转

删除重复的行并扭转

好吧,我想删除重复的行,但它比这更复杂一点..

我有一个名为 users.txt 的文件,文件示例是:

 users:[email protected]
 users1:[email protected]

现在,由于我的系统中的一个错误,人们可以使用与其他人相同的电子邮件地址进行注册,因此我想删除如果行多次具有相同电子邮件地址的情况,问题示例:

 user:display:[email protected]
 user2:[email protected]
 user3:[email protected]
 user4:[email protected]

请注意 user、user2、user3、user4 是如何拥有相同的电子邮件的。我想删除 user2、user3、user4 但保留 user.. 反之亦然(按请求选取第一个)删除包含相同电子邮件的任何其他行电子邮件..

因此,如果

 [email protected] is in 20 lines remove 19
 [email protected] is in 555 lines remove 554
 and so fourth..

答案1

这需要 awk。由于您要检查的字段是每行的第一个字段,因此只需引用$1.

awk -F: '! ($1 in seen) {print; seen[$1]}' users.txt

您可以“打高尔夫球”以大大减少它:

awk -F: '!a[$1]++' users.txt

较长的形式或多或少是不言自明的;您使用每个电子邮件地址作为索引构建一个关联数组,而无需费心分配值。然后,您可以检查电子邮件地址之前是否已“见过”(即,关联数组是否已将特定电子邮件地址作为索引),如果没有,则打印整行。

较短的形式实际上或多或少做了相同的事情,但需要对较短的代码进行更多解释。

后缀++运算符作用于变量表达式会被求值,所以我们稍后会再讨论这个问题。

在 awk 中,0 表示 false,非零表示 true。 !是为了否定并反转真值。

出现在大括号之外时,该表达式被解释为布尔表达式,如果表达式为 true,则执行关联的操作(在大括号中)。由于没有明确说明任何操作,因此使用打印整行的默认(隐式)操作,如果表达式的计算结果为真(非零)。

a本质上,这会检索关联数组中指向电子邮件地址(第一个字段)的值作为其索引,或者创建初始化为 0 的值(如果尚不存在),将 0 解释为 false 或将非零解释为 true,反转如果结果是“真值”,则打印整行,然后递增该点存储在关联数组中的值。

实际上,这是一个足够常见的 Awk 习惯用法,但我不会责怪您使用更长、更明确的版本。 :)

答案2

  1. 使用GNU datamash将输入分组为第二名字段,并仅保留每个分组的第一行:

    datamash -t':' -g 2 rmdup 2 < users.txt
    
  2. 作为来自的评论唐克里斯斯蒂注释,sort可以做到这一点,但是当它返回所需的结果时,它也可能会重新排序输出:

    sort -t':' -k 2,2 -u users.txt
    

上面的代码假设用户.txt按第二个字段排序,然后按第一个字段排序。

相关内容