在一个文件中查找重复行,并计算每行重复的次数?

691

假设我有一个类似以下内容的文件:

123 
123 
234 
234 
123 
345

我想找出'123'重复了多少次,'234'重复了多少次,等等。

理想情况下,输出结果应该是这样的:

123  3 
234  2 
345  1

6
我可以使用中文进行翻译。请问您希望翻译哪种语言? - VMAtm
7个回答

988
假设每行都有一个数字:
sort <file> | uniq -c

您也可以在GNU版本上使用更冗长的--count标志,例如,在Linux上:

sort <file> | uniq --count

3
这是我的做法,但从算法角度来看,这似乎不是最有效的方法(O(n log n)*avg_line_len,其中n是行数)。我正在处理几个GB大小的文件,因此性能是一个关键问题。我想知道是否有一种工具可以在单次扫描中仅使用前缀树(在我的情况下,字符串经常具有共同的前缀)或类似工具来进行计数,并且应该以O(n)*avg_line_len完成任务。有人知道这样的命令行工具吗? - Droggl
33
另外一步是将其输出导入到最后的 "sort -n" 命令中。这将按最常出现的行对结果进行排序。 - samoz
124
如果你只想打印重复的行,请使用'uniq -d'。 - DmitrySandalov
9
如果想再次对结果进行排序,您可以像这样再次使用 sort 命令:sort <文件> | uniq -c | sort -n - Abhishek Kashyap
4
如果 @DmitrySandalov 没有提到 -d,我会执行 ... | uniq -c | grep -v '^\s*1'-v 表示反向正则表达式,拒绝匹配(不是冗长的、不是版本的 :)))。 - Frank N
显示剩余4条评论

559
这将仅打印重复的行,并显示计数:
sort FILE | uniq -cd

或者,在Linux上使用GNU长选项:
sort FILE | uniq --count --repeated

BSD和OSX上,您需要使用grep来过滤出唯一的行:
sort FILE | uniq -c | grep -v '^ *1 '

对于给定的例子,结果将是:
  3 123
  2 234

如果您想打印所有行的计数,包括仅出现一次的行:
sort FILE | uniq -c

或者,使用GNU长选项(在Linux上):
sort FILE | uniq --count

对于给定的输入,输出结果为:
  3 123
  2 234
  1 345

为了将输出按照出现频率排序,使最常见的行位于顶部,您可以执行以下操作(以获取所有结果):
sort FILE | uniq -c | sort -nr

或者,要仅获取重复行,按最常见的顺序:
sort FILE | uniq -cd | sort -nr

在OSX和BSD上,最终的结果变成:
sort FILE | uniq -c | grep -v '^ *1 ' | sort -nr

1
使用--repeated或-d选项确实很不错。比起使用"|grep 2"或类似的方法要准确得多! - Lauri
如何修改这个命令以检索出重复计数超过100的所有行? - Black_Rider
@Black_Rider 在管道中添加 | sort -n| sort -nr 将按重复计数对输出进行排序(升序或降序)。这不是你要求的,但我认为它可能会有所帮助。 - Andrea
1
@Black_Rider awk似乎能够进行各种计算:在您的情况下,您可以执行 | awk '$1>100' - Andrea
4
看起来在 Mac 的 uniq 中,无法同时使用 -c 和 -d 选项。感谢您的指出。您可以使用 grep 命令来过滤唯一行:sort FILE | uniq -c | grep -v '^ *1 ' - Andrea
显示剩余4条评论

77

为了在多个文件中查找和计算重复的行,您可以尝试以下命令:

sort <files> | uniq -c | sort -nr
或:
cat <files> | sort | uniq -c | sort -nr

37

通过

awk '{dups[$1]++} END{for (num in dups) {print num,dups[num]}}' data
awk 'dups[$1]++'命令中,变量$1保存了列1的全部内容,方括号是数组访问符。因此,对于data文件中每一行的第一列,名为dups的数组节点都会递增。

最后,我们使用变量num循环遍历dups数组,并先打印已存储的数字,然后打印它们的重复值数量,即dups[num]

请注意,您的输入文件某些行末尾有空格,如果清理这些空格,则可以在上述命令中使用$0替换$1 :)


2
考虑到我们已经有了“uniq”,这是否有点过度设计了? - Nathan Fellman
14
“sort | uniq” 和 awk 解决方案在性能和资源权衡方面有很大的不同:如果文件很大且不同行的数量很少,则 awk 解决方案更加高效。它对行数是线性的,而对不同行数则是空间使用的线性。然而,awk 解决方案需要将所有不同的行保留在内存中,而(GNU) sort 可以利用临时文件来重新排序。 - Lars Noschinski

19

在Windows中,使用“Windows PowerShell”,我使用下面提到的命令来实现这个目标。

Get-Content .\file.txt | Group-Object | Select Name, Count

此外,我们可以使用where-object命令来过滤结果。

Get-Content .\file.txt | Group-Object | Where-Object { $_.Count -gt 1 } | Select Name, Count

你能删除所有重复的出现,除了最后一个,而不改变文件的排序顺序吗? - jparram
与下面类似,你当然也可以使用 ...| Sort -Top 15 -Descending Count | Select Name 来进行排序。 - undefined

16

要查找重复计数,请使用此命令:

sort filename | uniq -c | awk '{print $2, $1}'

7
假设您可以访问标准的Unix shell和/或cygwin环境:
tr -s ' ' '\n' < yourfile | sort | uniq -d -c
       ^--space char

基本上:将所有的空格字符转换为换行符,然后对翻译输出进行排序并将其提供给uniq以计算重复行数。

我猜这个解决方案是为你自己的特定情况量身定制的?也就是说,你有一个仅由空格或换行符分隔的单词列表。 如果它只是一个由换行符(没有空格)分隔的数字列表,那么它在那里运行得很好,但显然你的解决方案会以不同的方式处理包含空格的行。 - mwfearnley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接