删除重复的行而不进行排序

我有一个 Python 实用脚本:

#!/usr/bin/env python
import sys
unique_lines = []
duplicate_lines = []
for line in sys.stdin:
if line in unique_lines:
duplicate_lines.append(line)
else:
unique_lines.append(line)
sys.stdout.write(line)
# optionally do something with duplicate_lines

这个简单的功能(uniq不需要首先排序,稳定的排序)必须作为一个简单的 UNIX 实用程序提供,不是吗?也许是管道里的过滤器组合?

问这个问题的原因: 在一个我不能在任何地方执行 Python 的系统上需要这个功能。

76385 次浏览

UNIX Bash 脚本博客 暗示:

awk '!x[$0]++'

这个命令告诉 awk 要打印哪些行。变量 $0保存一行的全部内容,方括号是数组访问。因此,对于文件的每一行,数组 x的节点是递增的,如果之前没有设置该节点的内容(!) ,则打印该行。

迈克尔 · 霍夫曼的上述解决方案简短而甜蜜。对于较大的文件,包含添加索引字段的 Schwartzian 转换方法使用 awk,然后是多轮 sort 和 uniq,这种方法涉及较少的内存开销。下面的代码片段在 bash 中工作

awk '{print(NR"\t"$0)}' file_name | sort -t$'\t' -k2,2 | uniq --skip-fields 1 | sort -k1,1 -t$'\t' | cut -f2 -d$'\t'

谢谢1 _ CR!我需要一个“ uniq-u”(完全删除副本)而不是 uniq (留下一个副本)。Awk 和 perl 解决方案实际上不能修改为这样做,您的可以这样做!我可能还需要较低的内存使用,因为我将是唯一的喜欢100,000,000行8 -)。为了以防其他人需要它,我在命令的 uniq 部分中加了一个“-u”:

awk '{print(NR"\t"$0)}' file_name | sort -t$'\t' -k2,2 | uniq -u --skip-fields 1 | sort -k1,1 -t$'\t' | cut -f2 -d$'\t'

一个迟到的回答——我刚刚碰到了这个问题的复制品——但也许值得补充一下... ..。

@ 1 _ CR 答案背后的原理可以写得更简洁,用 cat -n代替 awk来添加行号:

cat -n file_name | sort -uk2 | sort -n | cut -f2-
  • 使用 cat -n预置行号
  • 使用 sort -u删除重复数据(-k2说“从字段2开始排序键”)
  • 使用 sort -n按照预设的数字进行排序
  • 使用 cut删除行号(-f2-说“选择字段2直到结束”)

我只是想删除以下行中的所有副本,而不是文件中的所有地方,所以我使用:

awk '{
if ($0 != PREVLINE) print $0;
PREVLINE=$0;
}'

从2个文件中删除重复的内容:

awk '!a[$0]++' file1.csv file2.csv

uniq命令在别名中工作,甚至在 http://man7.org/linux/man-pages/man1/uniq.1.html中也是如此

现在您可以查看用 Rust 编写的这个小工具: UQ

该方法不需要对输入进行排序就可以进行唯一性过滤,因此可以应用于连续流。

相对于热门的 awk 解决方案和其他基于 shell 的解决方案,这个工具有两个优点:

  1. uq使用散列值记住行的出现,因此当行很长时,它不会使用同样多的内存。
  2. uq可以通过设置存储条目的数量限制来保持内存使用常数(当达到这个限制时,有一个标志可以控制要么覆盖要么死亡) ,而 awk解决方案可能会在行太多时遇到 OOM。