如何使用 bash 删除文件中仅出现一次的行

How to remove lines appear only once in a file using bash

如何删除 bash 文件中只出现一次的行?

例如,文件 foo.txt 有:

1
2
3
3
4
5

处理文件后,仅

3
3

会留下来。

注意文件已经排序。

只需循环文件两次:

$ awk 'FNR==NR {seen[[=10=]]++; next} seen[[=10=]]>1' file file
3
3
  • 首先计算一行出现的次数:seen[ record ] 将其作为一个数组进行跟踪。
  • 其次打印出现多次的那些

使用单通道 awk:

awk '{freq[[=10=]]++} END{for(i in freq) for (j=1; freq[i]>1 && j<=freq[i]; j++) print i}' file

3
3
  • 使用freq[[=11=]]++我们计算并存储每一行​​的频率。
  • END 块中,如果 frequency 大于 1,那么我们打印这些行的次数与频率相同。

如果你重复的行是连续的,你可以使用uniq

uniq -D file

来自手册页:

-D print all duplicate lines

使用 awk,单遍:

$ awk 'a[[=10=]]++ && a[[=10=]]==2 {print} a[[=10=]]>1' foo.txt
3
3

如果文件是无序的,由于解决方案没有缓冲值,输出将按照在文件中找到重复项的顺序发生。

这是一个 POSIX 兼容的 awk 替代 GNU 特定 uniq -D:

awk '++seen[[=10=]] == 2; seen[[=10=]] >= 2' file

结果证明这只是 的一个较短的重新表述。

uniq 不同,此命令并不 严格地 要求对重复项进行分组,但输出顺序只有在分组时才可预测。

也就是说,如果不对重复项进行分组,则输出顺序由每组重复项中 2nd 个实例的相对顺序决定,并且在每个集合中第一个和第二个实例将一起打印。

对于未排序(未分组)数据(如果保留输入顺序也很重要),请考虑:

  • (优雅,但需要读取文件两次
  • (single-pass方案,但稍微麻烦一点)。