如果行在特定列的所有文件中仅包含一次模式,如何删除该行

如果行在特定列的所有文件中仅包含一次模式,如何删除该行

我的文件包含几列,第一列对应于 id。如果 id 在整个文件中仅出现一次(在第一列中),我想删除一行。如果 id 多次出现,我想将该行保留在文件中。 id 由字母(有时是数字)组成,以 A 开头(所有其他字母/数字均为随机顺序)。例如 :A2SGWS7CUGU8GB

如果我有 :

# id             #column 2 ...
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
ADE8GST9URWPOS
ABXLMWJCQFGVXV
A2SGWS7CUGU8GB

我想删除包含ADE8GST9URWPOSand的行,ABXLMWJCQFGVXV因为它们只出现一次。我怎么能这样做呢?

答案1

首先,这将返回所有重复的并且您想要保留的 ID:

$ awk '{ print $1 }' <file | sort | uniq -d
A2SGWS7CUGU8GB

它通过使用 . 提取第一个空白分隔字段(ID)来实现这一点awk。然后对其进行排序并uniq -d用于仅输出重复的 ID。

然后,我们可以使用这些(在本例中为单数)ID 从原始文件中提取相应的行,首先必须使用以下方法对原始文件进行排序join

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file )
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

如果您的 shell 不支持使用 进行进程替换<(...),您可以使用临时文件分两步执行此操作:

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

使用仅有的 awk,这可以通过以下方式完成:

$ awk 'NR == FNR { count[$1]++; next } count[$1] > 1' file file
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

请注意,该文件在命令行中被提及两次,因为代码已读取该文件两次awk

第一次,关联数组count由每个 ID 出现的次数填充,第二次,输出具有多次出现的 ID 的每行。

上述两种方法的区别在于,awk最后给出的命令将保留原始数据的顺序,但会消耗与唯一 ID 数量成比例的内存。第一种方法将生成排序结果,可能更适合很大数据。


为了保留标题行,需要稍微修改命令:

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file ) | cat <(head -1 file) -

或者

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted > file.noheader
$ head -1 file | cat - file.noheader

或者

$ awk 'NR == 1 ; NR == FNR { count[$1]++; next } count[$1] > 1' file file

答案2

awk '
  !B {a[$1]++}
  B && a[$1] > 1
' B=0 file B=1 file

获取第一个字段(=ID)并对它进行排序,然后统一 ID 并仅保留重复的 ID。将它们传递给 xargs 并根据每个此类 ID 创建一个 egrep ERE 正则表达式。

< file \
  cut -d" " -f1          \
| sort  | uniq -d        \
| xargs -I{} echo ^{}\\s \
| grep -Ef - file        \
;

使用perl我们slurp文件-0777选项并通过记录运行正则表达式,如果在每行开头^,我们能够看到更下面的第一个字段(= ID)或者之前已经遇到过ID,则打印当前行

perl -0777ne '
  () = m/(?msx)
      ^
      (?<line>
        (?<ID> A\w+)
        \h.*?\n
      )

      (?=
        (?:.*?\n)?
        (?<lukahead> \g{ID}|$)
      )

      (?{ my %seen;
        my($id_visible_ahead, $id_already_seen) =
          map { $_ > 0 } 
length($+{lukahead}), $seen{$+{ID}};

        print($+{line}),$seen{$+{ID}}++
          if $id_visible_ahead || $id_already_seen;
      })
   /g;
' file

输出:

A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

相关内容