我有一个字符串文件:
string-string-123
string-string-123
string-string-123
string-string-12345
string-string-12345
string-string-12345-123
如何在bash(string-string-123
)中检索最常见的行?
答案 0 :(得分:13)
您可以将sort
与uniq
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,\} //'
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/...//
表示前缀替换为空字符串,即有效已删除。