Pertanyaan Menyortir menurut jumlah pengulangan


Saya memiliki file yang terlihat seperti ini:

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

Saya membuat semua angka.

Saya harus mengurutkan semua file ini sesuai dengan jumlah pengulangan ip pertama. Jadi hasilnya idealnya akan terlihat seperti ini:

192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1

Jadi: ip pertama, semua port yang ada di garis dengan ip pertama, dan jumlah pengulangan.

Saya sudah mencoba untuk bermain dengan perintah semacam dan awk tapi saya tidak ingin melakukan pekerjaan tambahan dan mungkin kehilangan beberapa solusi langsung lainnya.

Ada ide? Terima kasih :)


4
2017-12-15 10:27


asal


Jawaban:


Jawaban Perlish akan terlihat seperti ini.

#!/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

Keluaran:

192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1

7
2017-12-15 10:51



Cara 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

keluaran:

192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1

2
2017-12-15 10:38



Solusi Perl lain:

#!/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

Keluaran:

192.168.2.2 8080 369 457 3
192.168.489.2 8080 80 2
192.168.12.25 50 1

1
2017-12-15 11:15



baris ini harus melakukan pekerjaan untuk Anda:

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-

uji dengan teladan Anda

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

0
2017-12-15 11:06



Berikut adalah saluran pipa yang mengandalkan terutama pada awk dan sortir:

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
2017-12-15 11:37



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

0
2017-12-15 14:04