在 bash 中查找文件中最常见的行

Find the most common line in a file in bash

我有一个字符串文件:

string-string-123
string-string-123
string-string-123
string-string-12345
string-string-12345
string-string-12345-123

如何检索 bash (string-string-123) 中最常见的行?

您可以使用 awk 来执行此操作:

awk '{++a[[=10=]]}END{for(i in a)if(a[i]>max){max=a[i];k=i}print k}' file

数组a 保留每一行的计数。一旦文件被读取,我们循环遍历它并找到具有最大计数的行。

或者,您可以通过在文件处理期间分配行来跳过 END 块中的循环:

awk 'max < ++c[[=11=]] {max = c[[=11=]]; line = [=11=]} END {print line}' file

感谢 glenn jackman 提出这个有用的建议。


正确地指出,在平局的情况下,上述两种方法只会打印出最常出现的行之一。以下版本将打印出所有最常出现的行:

awk 'max<++c[[=12=]] {max=c[[=12=]]} END {for(i in c)if(c[i]==max)print i}' file

您可以将 sortuniq

一起使用
sort file | uniq -c | sort -n -r
  • 效果很好 [在修改后的版本中打印 all 平局时最常出现的行]。
    但是,它可能不适合大文件,因为所有 distinct 输入行都存储在内存中的关联数组中,如果有很多非重复行,这可能会成为问题;也就是说,它比下面讨论的方法

  • 优雅地组合多个实用程序以 隐式地 产生所需的结果,但是:

    • 打印所有 行不同的行(最高频率优先)
    • 输出行以它们的出现次数为前缀(这实际上可能是可取的)。

虽然您可以通过管道将 传输到 head 以限制显示的行数,但您不能假定一般的 固定 行数.

基于 Grzegorz 的回答,这里有一个通用的 解决方案,显示 所有 最常出现的行 - 不管有多少行 - 和 只有 他们:

sort file | uniq -c | sort -n -r | awk 'NR==1 {prev=} !=prev {exit} 1'

如果您不希望输出行以出现次数为前缀:

sort file | uniq -c | sort -n -r | awk 'NR==1 {prev=} !=prev {exit} 1' | 
  sed 's/^ *[0-9]\{1,\} //'

的解释:

  • uniq -c 输出一组 唯一的 输入行 以它们各自的出现次数为前缀 (-c) ,后跟一个 space.
  • sort -n -r 然后按数字 (-n) 降序 (-r) 对结果行进行排序,以便最常出现的行位于顶部。
    • 注意sort,如果没有指定-k,一般会尝试按整个输入行排序,但是-n导致仅被识别为整数的最长前缀用于排序,这正是这里所需要的。

我的 awk 命令的解释:

  • NR==1 {prev=} 将第一个白色 space 分隔字段 (</code>) 存储在变量 <code>prev 中,用于 first 输入行 (NR==1)
  • !=prev {exit} 终止处理,如果第一个白色 space 分隔的字段与上一行的不同 - 这意味着已经到达非最顶行,并且没有更多行需要打印。
  • 1 是 shorthand for { print } 意味着手头的输入行应该按原样打印。

我的 sed 命令的解释:

  • ^ *[0-9]\{1,\} 匹配每个输出行的数字前缀(表示出现次数),(最初)由 uniq -c
  • 生成
  • applying s/...// 意味着前缀被替换为 空字符串,即有效地 removed.