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