【发布时间】:2015-06-01 23:34:57
【问题描述】:
我有一个字符串文件:
string-string-123
string-string-123
string-string-123
string-string-12345
string-string-12345
string-string-12345-123
如何检索 bash (string-string-123) 中最常见的行?
【问题讨论】:
标签: 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) 中最常见的行?
【问题讨论】:
标签: linux bash text-processing
您可以将sort 与uniq 一起使用
sort file | uniq -c | sort -n -r
【讨论】:
您可以使用 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
【讨论】:
awk '{if (max < ++c[$0]) {max = c[$0]; line = $0}} END {print line}'
sort / uniq 方法快得多。
awk '{b[a[$0]++]=$0}END{asort(b);print b[1]}'
Tom Fenech's elegant awk answer 工作得很好[在打印所有在出现平局时最常出现的行的修正版本中]。
但是,它可能不适合大文件,因为所有 distinct 输入行都存储在内存中的关联数组中,如果有很多非重复行,这可能会出现问题;也就是说,它比下面讨论的方法快。
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,\} //'
uniq -c 输出一组唯一输入行,以各自的出现次数为前缀 (-c),后跟一个空格。sort -n -r 然后按数字 (-n) 降序 (-r) 对结果行进行排序,以便最常出现的行位于顶部。
sort,如果未指定-k,一般会尝试按整个输入行排序,但-n只会导致被识别的最长前缀作为用于排序的整数,这正是这里所需要的。解释我的awk 命令:
NR==1 {prev=$1} 将第一个空格分隔字段 ($1) 存储在变量 prev 中,用于 first 输入行 (NR==1)$1!=prev {exit} 终止处理,如果第一个空格分隔的字段与前一行的不同 - 这意味着已到达非最上面的行,不再需要打印行。1 是 { print } 的简写,表示手头的输入行应按原样打印。解释我的sed 命令:
^ *[0-9]\{1,\} 匹配每个输出行的数字前缀(表示出现次数),如(最初)由 uniq -c 生成的 s/...// 意味着前缀被替换为空字符串,即有效地移除。【讨论】: