使用命令行工具计算已排序序列中的重复项

98

我有一个命令(cmd1),可以通过对日志文件进行grep来过滤出一组数字。这些数字是无序的,因此我使用sort -gr来获得数字的反向排序列表。这个排序列表中可能存在重复项。我需要找到该列表中每个唯一数字的计数。

例如,如果cmd1的输出为:

100 
100 
100 
99 
99 
26 
25 
24 
24
我需要另一个可以将上述输出作为管道输入的命令,以便我获得以下结果:
100     3
99      2
26      1
25      1
24      2

使用命令行工具计算排序序列中的重复项 - David Cary
相关:https://dev59.com/32w15IYBdhLWcg3wSJvQ#16980265 - rogerdpack
7个回答

118

怎么样?

$ echo "100 100 100 99 99 26 25 24 24" \
    | tr " " "\n" \
    | sort \
    | uniq -c \
    | sort -k2nr \
    | awk '{printf("%s\t%s\n",$2,$1)}END{print}'

结果如下:
100 3
99  2
26  1
25  1
24  2

1
我运行了这个程序,它在结尾处产生了一个额外的打印语句$1,$2: 100 3 99 2 26 1 25 1 24 2 2 24 - Mittenchops
3
以下代码在结果之间添加了一个新行并删除了末尾的额外行:echo "100 100 100 99 99 26 25 24 24" | tr " " "\n" | sort | uniq -c | sort -k2nr | awk '{printf("%s\t%s\n",$2,$1)}END{print}' | head -n -1,因此您将得到以下输出:100 3 99 2 26 1 25 1 24 2 - Woody
关于语法的注意事项,您可以使用竖线来结束一行,而不必使用反斜杠。 - wjandrea

69

uniq -c适用于至少版本为GNU uniq 8.23的系统,并且可以完全满足你的需求(假设输入已经排序)。


3
如果输入内容没有排序,那么只需添加sort命令:sort file_name | uniq -c - Mikhail Geyer
太棒了。也适用于Mac OS X!在Mojave 10.14.6上进行了测试。 - bappak

11

如果顺序不重要

# echo "100 100 100 99 99 26 25 24 24" | awk '{for(i=1;i<=NF;i++)a[$i]++}END{for(o in a) printf "%s %s ",o,a[o]}'
26 1 100 3 99 2 24 2 25 1

如果您能不使用3个管道符号来完成这个操作,那将会非常棒。如果您能详细解释一下它的工作原理,那将更好,因为它让我感到有些困惑。;-) 谢谢。 - SaxDaddy

10

将数字按相反顺序进行数值排序,然后计算重复项,接着交换左右单词的位置。最后对齐成列。

printf '%d\n' 100 99 26 25 100 24 100 24 99 \
   | sort -nr | uniq -c | awk '{printf "%-8s%s\n", $2, $1}'
100     3
99      2
26      1
25      1
24      2

2
在Bash中,我们可以使用关联数组来统计每个输入值的实例。假设我们有命令$cmd1,例如:
#!/bin/bash

cmd1='printf %d\n 100 99 26 25 100 24 100 24 99'

然后,我们可以使用适当的数组项上的++数学运算符来计算数组变量a中的值:

while read i
do
    ((++a["$i"]))
done < <($cmd1)

我们可以打印出结果值:
for i in "${!a[@]}"
do
    echo "$i ${a[$i]}"
done

如果输出的顺序很重要,我们可能需要对键进行外部的排序
for i in $(printf '%s\n' "${!a[@]}" | sort -nr)
do
    echo "$i ${a[$i]}"
done

1

如果您在my_file中存储了输入,您可以执行以下操作:

sort -nr my_file | uniq -c | awk ' { t = $1; $1 = $2; $2 = t; print; } '

否则,只需将要处理的输入导入到同一个命令中即可。
解释:
- `sort -nr` 对输入进行数字排序(`-n`),按相反顺序排序(`-r`) - `uniq -c` 计算重复项并显示计数 - `awk '{ t = $1; $1 = $2; $2 = t; print; }'` 交换两列。

0
Ruby在内部具有从命令行高效执行此操作的工具。
例如,给定以下文件:
$ cat file
100 
100 
100 
99 
99 
26 
25 
24 
24
1

计算每个; 按照a) 出现次数递减 b) 值递减排序; 放在排列整齐的列中。这是Ruby实现的代码:
ruby  -e '
cnt=Hash.new(0)
$<.each{|x| cnt[x.to_i]+=1}
w1,w2=cnt.max_by{|e| e.to_s.length}.map{|e| e.to_s.length+2}
cnt.sort_by{|k,v| [-v,-k]}.each{|k,v| 
            puts "#{k.to_s.rjust(w1," ")}\t#{v.to_s.rjust(w2," ")}"
}' file

输出:

  100     3
   99     2
   24     2
   26     1
   25     1
    1     1

输入文件不需要排序。

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