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

时间:2015-03-28 18:35:55

标签: linux bash text-processing

我有一个字符串文件:

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

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

3 个答案:

答案 0 :(得分:13)

您可以将sortuniq

一起使用
sort file | uniq -c | sort -n -r

答案 1 :(得分:5)

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

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

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

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

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

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


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

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

答案 2 :(得分:3)

  • Tom Fenech's elegant awk answer效果很好[在修正后的版本中打印所有最常出现的行,如果出现平局]。
    但是,它可能不适合大文件,因为所有不同输入行都存储在内存中的关联数组中,如果存在许多非重复行,则可能会出现问题。也就是说,它比下面讨论的方法更快

  • Grzegorz Żur's answer优雅地将多个实用程序组合到隐式生成所需结果,但是:

    • 打印所有不同的行(首先是最高频率计数)
    • 输出行以其出现次数为前缀(实际上可能是理想的)。

虽然您可以将Grzegorz Żur's answer传递给head以限制显示的行数,但您通常不能假设固定的行数。

在Grzegorz的答案的基础上,这是一个通用的解决方案,显示所有最频繁出现的行 - 无论有多少 - 而他们

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

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

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

Grzegorz Żur's answer的解释:

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

我的awk命令的说明:

  • NR==1 {prev=$1}将第一个以空格分隔的字段($1)存储在变量prev中,用于第一个输入行(NR==1
  • $1!=prev {exit}终止处理,如果第一个空格分隔的字段与前一行不同 - 这意味着已经到达非最顶层的行,并且不再需要打印行。
  • 1{ print }的简写,意味着手边的输入行应按原样打印。

我的sed命令的说明:

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