135

我在 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 的系统上需要此功能。

4

8 回答 8

325

UNIX Bash 脚本博客建议

awk '!x[$0]++'

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

于 2012-07-17T23:17:57.680 回答
83

一个迟到的答案 - 我刚刚遇到了这个的副本 - 但也许值得添加......

@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 直到结束”)
于 2013-12-17T16:39:11.537 回答
8

要从 2 个文件中删除重复项:

awk '!a[$0]++' file1.csv file2.csv
于 2017-08-22T03:32:34.830 回答
5

上面迈克尔霍夫曼的解决方案简短而甜蜜。对于较大的文件,Schwartzian 变换方法涉及使用 awk 添加索引字段,然后进行多轮排序和 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'
于 2012-07-23T16:43:38.393 回答
4

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

它执行唯一性过滤而不必先对输入进行排序,因此可以应用于连续流。

与投票率最高的 awk 解决方案和其他基于 shell 的解决方案相比,此工具有两个优点:

  1. uq使用它们的哈希值记住行的出现,因此当行很长时它不会使用太多的内存。
  2. uq可以通过设置要存储的条目数量限制来保持内存使用量不变(当达到限制时,有一个标志可以控制覆盖或死亡),而awk当存在太多时解决方案可能会遇到OOM线。
于 2018-04-30T08:45:33.680 回答
2

谢谢 1_CR!我需要一个“uniq -u”(完全删除重复项)而不是 uniq(保留 1 个重复项)。不能真正修改 awk 和 perl 解决方案来做到这一点,你可以!我可能还需要较低的内存使用,因为我将像 100,000,000 行一样 uniq'ing 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'
于 2013-10-23T18:26:14.093 回答
-1

我只是想删除以下行中的所有重复项,而不是文件中的所有位置。所以我用:

awk '{
  if ($0 != PREVLINE) print $0;
  PREVLINE=$0;
}'
于 2016-02-05T10:08:41.223 回答
-1

uniq命令甚至可以使用别名http://man7.org/linux/man-pages/man1/uniq.1.html

于 2017-10-06T11:03:21.043 回答