Ordenar y agrupar dominios y subdominios

Ordenar y agrupar dominios y subdominios

¿Existe una mejor manera de ordenar y agrupar dominios y subdominios? Por ejemplo, el archivo listque contiene

morefu.sub1.foo.com
www.foo.com
bar.foo.com
sub1.foo.com 
fufu.isub1.foo.com
foofoo.bar.foo.com 
morefoo.bar.foo.com
fufu.sub1.foo.com

usando

for i in $(grep -oP '(\w+).foo.com' list | sort | uniq); do grep $i list | sort; echo; done

casi funciona:

bar.foo.com
foofoo.bar.foo.com 
lotsmorefubar.bar.foo.com
morefoo.bar.foo.com

fufu.isub1.foo.com <-- should not be here
fufu.sub1.foo.com
morefu.sub1.foo.com
sub1.foo.com 

www.foo.com

a excepción de fufu.isub1.foo.comque debería estar en una sección aparte. Agregar ^y \ba la expresión grep no ayudó.

¿Se pregunta si existe una forma más precisa y eficiente de hacer esto?

Respuesta1

Qué tal si

tr -d [:blank:] < hosts |                           # remove trailing whitespace
perl -lne 'print join ".", reverse(split /\./)' |   # reverse order of fields
sort |                                              # sort
awk -F. '
  !seen[$1.$2.$3]++ && NR>1 {print ""}             # insert blank line when tld,dom,sub change
  {for (i=NF;i>1;i--) printf "%s.", $i; print $1}   # print fields in original order
'

donación

bar.foo.com
foofoo.bar.foo.com
morefoo.bar.foo.com

fufu.isub1.foo.com

sub1.foo.com
fufu.sub1.foo.com
morefu.sub1.foo.com

www.foo.com

Mejor (espero) implementación del mismo algoritmo, usando unhash de hashesen Perl:

#!/usr/bin/perl

use strict;
use warnings;

my %domains = ();

while (defined($_ = <ARGV>)) {
  chomp $_ ;
  $_ =~ s/\s+//;

  my @F = reverse(split(/\./));
  my $domain = join(".", @F[0..2]);

  if ( ! exists($domains{$domain}) ) {
    $domains{$domain} = {};
  }

  $domains{$domain}{join(".", @F)}++;
}

foreach my $domain (sort keys %domains) {
  foreach my $host (sort keys %{ $domains{$domain} }) {
    print join(".", reverse(split(/\./, $host))), "\n";
  }
  print "\n"
}

Respuesta2

TXRCeceo:

[(opip (mapcar (op tok-str @1 #/[^.]+/))
       (sort @1 : reverse)
       (partition-by (ret [@1 -3..-1]))
       (mapcar (op mapcar (op cat-str @1 ".")))
       (interpose "")
       tprint)
 (get-lines)]

Correr:

$ txr domain-sort.tl < data
bar.foo.com
foofoo.bar.foo.com
morefoo.bar.foo.com

fufu.isub1.foo.com

sub1.foo.com
fufu.sub1.foo.com
morefu.sub1.foo.com

www.foo.com

Básicamente, tokenizamos las líneas en listas de cadenas como ("sub1" "foo" "com")y trabajamos con una lista de ellas. Ordenamos esta lista usando el reverso de sus elementos como clave; por lo que, a los efectos de la clasificación, ("sub1" "foo" "com")se trata como si lo fuera ("com" "sub1" "foo"). Después de eso, es cuestión de agruparse. Esto se logra fácilmente usando partition-by, utilizando los últimos tres elementos como clave de partición. Tenemos que reconstituir las cadenas uniéndolas con un punto e imprimir los grupos con líneas. Esto último se logra insertando una cadena vacía entre los grupos y dejando que tprinthaga su trabajo.

información relacionada