提问人:coconut 提问时间:12/15/2011 最后编辑:coconut 更新时间:12/15/2011 访问量:232
按重复次数排序
Sorting by number of repetitions
问:
我有一个文件,如下所示:
192.168.2.2 150.25.45.7 8080
192.168.12.25 178.25.45.7 50
192.168.2.2 142.55.45.18 369
192.168.489.2 122.25.35.7 8080
192.168.489.2 90.254.45.7 80
192.168.2.2 142.55.45.18 457
我编造了所有的数字。
我需要根据第一个 ip 的重复次数对所有这些文件进行排序。因此,理想情况下,输出将如下所示:
192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1
所以:第一个 ip,与第一个 ip 对齐的所有端口,以及重复次数。
我一直在尝试使用 sort 命令和 awk,但我不想做额外的工作,可能会错过其他一些简单的解决方案。
有什么想法吗?谢谢:)
答:
2赞
Toto
12/15/2011
#1
Perl 方式:
#!/usr/bin/perl
use strict;
use warnings;
my %repeat;
while(<DATA>) {
if (/^(\d+(?:.\d+){3})\s\S+\s(\d+)$/) {
push @{$repeat{$1}}, $2;
}
}
foreach (sort {@{$repeat{$b}}<=>@{$repeat{$a}}} keys %repeat) {
my $num = @{$repeat{$_}};
print "$_ @{$repeat{$_}} $num\n";
}
__DATA__
192.168.2.2 150.25.45.7 8080
192.168.12.25 178.25.45.7 50
192.168.2.2 142.55.45.18 369
192.168.489.2 122.25.35.7 8080
192.168.489.2 90.254.45.7 80
192.168.2.2 142.55.45.18 457
输出:
192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1
评论
0赞
Dave Cross
12/15/2011
我认为您错过了按每个源 IP 地址的出现次数对输出进行排序的要求。
1赞
Toto
12/15/2011
@davorg:是的,我做到了。更新了答案。
7赞
Dave Cross
12/15/2011
#2
Perlish 的答案看起来像这样。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my %data;
# Store IP address and port number
while (<DATA>) {
chomp;
my ($ip, undef, $port) = split;
push @{$data{$ip}}, $port;
}
# Sort (in reverse) by length of list of ports
for (sort { @{$data{$b}} <=> @{$data{$a}} } keys %data) {
say "$_ @{$data{$_}} ", scalar @{$data{$_}};
}
__DATA__
192.168.2.2 150.25.45.7 8080
192.168.12.25 178.25.45.7 50
192.168.2.2 142.55.45.18 369
192.168.489.2 122.25.35.7 8080
192.168.489.2 90.254.45.7 80
192.168.2.2 142.55.45.18 457
输出:
192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1
评论
0赞
coconut
1/29/2012
像魅力一样工作!你能解释一下 <=> 部分的作用吗?我很好奇。谢谢!
0赞
Dave Cross
2/2/2012
阅读 sort (perldoc.perl.org/functions/sort.html) 的文档和 perlop 中关于相等运算符 (perldoc.perl.org/perlop.html#Equality-Operators) 的部分。
0赞
Kent
12/15/2011
#3
这条线应该可以为您完成这项工作:
awk '{a[$1]++;b[$1]=b[$1]" "$3}END{for(x in a)print a[x]"\t"x,b[x],a[x]}' input |
sort -nr|cut -f2-
使用示例进行测试
kent$ cat tt
192.168.2.2 150.25.45.7 8080
192.168.12.25 178.25.45.7 50
192.168.2.2 142.55.45.18 369
192.168.489.2 122.25.35.7 8080
192.168.489.2 90.254.45.7 80
192.168.2.2 142.55.45.18 457
kent$ awk '{a[$1]++;b[$1]=b[$1]" "$3}END{for(x in a)print a[x]"\t"x,b[x],a[x]}' tt |
sort -nr|cut -f2-
192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1
1赞
flesk
12/15/2011
#4
另一个 Perl 解决方案:
#!/usr/bin/perl
use strict;
use warnings;
my %ips;
push @{$ips{$_->[0]}}, $_->[1]+0 for map{[split/ \S+ /]}<DATA>;
for (sort {@{$ips{$b}} <=> @{$ips{$a}}} keys %ips) {
printf("%s %s %d\n", $_, join(" ", @{$ips{$_}}), 0+@{$ips{$_}});
}
__DATA__
192.168.2.2 150.25.45.7 8080
192.168.12.25 178.25.45.7 50
192.168.2.2 142.55.45.18 369
192.168.489.2 122.25.35.7 8080
192.168.489.2 90.254.45.7 80
192.168.2.2 142.55.45.18 457
输出:
192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1
0赞
Michael J. Barber
12/15/2011
#5
下面是一个主要依赖于 awk 和 sort 的管道:
sort -k1 -k3n \
| awk -F' ' '
NR==1 {
printf("%s ", $1);
current = $1
}
$1 != current {
printf(":%d\n%s ", count, $1);
current = $1;
count = 0
}
{ printf("%d ", $3); count++ }
END { printf(":%d\n", count) }' \
| sort -t':' -k2nr \
| tr -d':'
0赞
Dimitre Radoulov
12/15/2011
#6
GNU awk 4:
awk 'END {
PROCINFO["sorted_in"] = "@val_num_desc"
for (e in ic)
print e, ip[e], ic[e]
}
{
ip[$1] = $1 in ip ? ip[$1] OFS $NF : $NF
ic[$1]++
}' infile
上一个:从列表中筛选具有相同成员的对象
下一个:查找具有相似和不同字段的记录
评论