Ordenar una lista de nombres de dominio (FQDN) comenzando desde tld y trabajando a la izquierda

20

Estoy buscando ordenar una lista de nombres de dominio (una lista blanca de filtro web) comenzando desde el TLD y trabajando hacia arriba. Estoy buscando herramientas * nix o windows que puedan hacer esto fácilmente, aunque un script también estaría bien.

Entonces, si es la lista que se te da

www.activityvillage.co.uk 
ajax.googleapis.com 
akhet.co.uk 
alchemy.l8r.pl 
au.af.mil 
bbc.co.uk 
bensguide.gpo.gov 
chrome.angrybirds.com 
cms.hss.gov 
crl.godaddy.com 
digitalhistory.uh.edu 
digital.library.okstate.edu 
digital.olivesoftware.com

Esto es lo que quiero como salida.

chrome.angrybirds.com 
crl.godaddy.com 
ajax.googleapis.com 
digital.olivesoftware.com 
digital.library.okstate.edu 
digitalhistory.uh.edu 
bensguide.gpo.gov 
cms.hss.gov 
au.af.mil 
alchemy.l8r.pl 
www.activityvillage.co.uk 
akhet.co.uk 
bbc.co.uk

En caso de que se pregunte por qué, Squidguard, tiene un error / falla de diseño. Si ambos www.example.comy ambos example.comestán incluidos en una lista, la example.comentrada se ignora y solo puede visitar el contenido www.example.com. Tengo varias listas grandes que necesitan limpieza porque alguien agregó entradas sin mirar primero.

Zoredache
fuente
¿No deberían comaparecer los dominios antes eduen su lista ordenada?
Sven
99
Sí, fallo en la clasificación manual, por eso estoy buscando una herramienta. :)
Zoredache
3
Además, la versión de Python allí es agradable en comparación con la versión de Perl porque el tipo de Python funciona en listas de listas; el tipo de perl no lo hace y tuvo que implementarse.
Mark Wagner
1
En una nota al margen, esto sería mucho más desafiante si OP hubiera pedido que los dominios superiores de acuerdo con la lista de sufijos públicos de Mozilla ( publicsuffix.org ) se manejen como un bloque. En algún momento podría hacerlo (sería bueno tenerlo para un proyecto), ¿alguien más interesado?
phk

Respuestas:

15

Este simple script de Python hará lo que quieras. En este ejemplo, nombro el archivo domain-sort.py:

#!/usr/bin/env python
from fileinput import input
for y in sorted([x.strip().split('.')[::-1] for x in input()]): print '.'.join(y[::-1])

Para ejecutarlo use:

cat file.txt | ./domain-sort.py

Tenga en cuenta que esto se ve un poco más feo, ya que escribí esto como más o menos una línea simple. Tuve que usar la notación de corte de[::-1] dónde funcionan los valores negativos para hacer una copia de la misma lista en orden inverso en lugar de usar el más declarativo reverse()que lo hace en el lugar de una manera que rompe la componibilidad.

Y aquí hay una versión un poco más larga, pero tal vez más legible, que utiliza la reversed()que devuelve un iterador, de ahí la necesidad de envolverla list()para consumir el iterador y producir una lista:

#!/usr/bin/env python
from fileinput import input
for y in sorted([list(reversed(x.strip().split('.'))) for x in input()]): print '.'.join(list(reversed(y)))

En un archivo con 1,500 líneas ordenadas al azar, toma ~ 0.02 segundos:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.02
Maximum resident set size (kbytes): 21632

En un archivo con 150,000 líneas ordenadas al azar, toma un poco más de 3 segundos:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.20
Maximum resident set size (kbytes): 180128

Aquí hay una versión posiblemente más legible que hace reverse()y sort()en el lugar, pero se ejecuta en la misma cantidad de tiempo, y en realidad toma un poco más de memoria.

#!/usr/bin/env python
from fileinput import input

data = []
for x in input():
   d = x.strip().split('.')
   d.reverse()
   data.append(d)
data.sort()
for y in data:
   y.reverse()
   print '.'.join(y)

En un archivo con 1,500 líneas ordenadas al azar, toma ~ 0.02 segundos:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.02
Maximum resident set size (kbytes): 22096

En un archivo con 150,000 líneas ordenadas al azar, toma un poco más de 3 segundos:

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.08
Maximum resident set size (kbytes): 219152
aculich
fuente
Me gustó ver muchas soluciones. Estoy aceptando la respuesta basada en Python principalmente porque es lo que uso para muchos de mis otros scripts. Las otras respuestas parecen funcionar también.
Zoredache
1
Si alguien está interesado en ordenar primero por nombre de dominio, ignorando TLD, usedata.sort(key=lambda x: x[1:])
Calimo
9

Aquí hay un script de PowerShell que debe hacer lo que quieras. Básicamente, arroja todos los TLD en una matriz, invierte cada TLD, lo ordena, lo revierte a su orden original y luego lo guarda en otro archivo.

$TLDs = Get-Content .\TLDsToSort-In.txt
$TLDStrings = @();

foreach ($TLD in $TLDs){
    $split = $TLD.split(".")
    [array]::Reverse($split)
    $TLDStrings += ,$split
}

$TLDStrings = $TLDStrings|Sort-Object

foreach ($TLD in $TLDStrings){[array]::Reverse($TLD)}

$TLDStrings | %{[string]::join('.', $_)} | Out-File .\TLDsToSort-Out.txt

Lo ejecutó en 1,500 registros: tomó 5 segundos en un escritorio razonablemente potente.

Mark Henderson
fuente
Creo que debería ser bastante simple convertir este script a bash u otro idioma.
Mark Henderson
5 segundos parece mucho tiempo para solo 1,500 líneas. Mi implementación de Python hace 1,500 en una fracción de segundo y 150,000 en poco más de 3 segundos. ¿Qué crees que lo hace tan lento en PowerShell?
aculich
Sí, es mucho tiempo Sin embargo, no tengo idea de por qué lleva tanto tiempo. Probablemente porque powershell no está realmente dirigido a hacer cosas como esta.
Mark Henderson
7

cat domain.txt | rev | ordenar | Rvdo

usuario3721740
fuente
Supongo que eso funcionaría. Sin embargo, me gusta que se ordene el TLD, y esto no lograría eso. Usando esto, los TLD en mi ejemplo estarían en el orden (uk, mil, pl, com, edu, gov), ya que es una ordenación simple de derecha a izquierda, en lugar de los límites del dominio.
Zoredache
¡La mejor respuesta que he visto!
Daniel
1
rev domain.txt|sort|rev
Rico
6

Un poco menos críptico, o al menos más bonito, Perl:

use warnings;
use strict;

my @lines = <>;
chomp @lines;

@lines =
    map { join ".", reverse split /\./ }
    sort
    map { join ".", reverse split /\./ }
    @lines;

print "$_\n" for @lines;

Este es un ejemplo simple de una transformación de Guttman-Rosler : convertimos las líneas en la forma ordenable apropiada (aquí, dividimos el nombre de dominio en puntos y revertimos el orden de las partes), las ordenamos usando el orden lexicográfico nativo y luego convertimos el líneas de regreso a su forma original.

Ilmari Karonen
fuente
6

En Unix scripting: reverse, sort y reverse:

awk -F "." '{for(i=NF; i > 1; i--) printf "%s.", $i; print $1}' file |
  sort |
  awk -F "." '{for(i=NF; i > 1; i--) printf "%s.", $i; print $1}'
jfg956
fuente
Algo similar con un solo bucle: awk -F. '{for(i=NF;i>0;i--){printf ".%s",$i};printf "\t%s\n",$0}' file|sort|cut -f2puede querer eliminar primero a los hosts locales congrep \. file | awk ...
Rich
3

Aquí está en perl (corto y críptico):

#!/usr/bin/perl -w
@d = <>; chomp @d;
for (@d) { $rd{$_} = [ reverse split /\./ ] }
for $d (sort { for $i (0..$#{$rd{$a}}) {
        $i > $#{$rd{$b}} and return 1;
        $rd{$a}[$i] cmp $rd{$b}[$i] or next;
        return $rd{$a}[$i] cmp $rd{$b}[$i];
} } @d) { print "$d\n" }
Mark Wagner
fuente
¿Tiene información de tiempo para este tipo? Tengo curiosidad por ver cómo esto se compara con la implementación de PowerShell de @ Mark-Henderson , así como con mi implementación de Python . Utilicé /usr/bin/time -vel tiempo transcurrido y las estadísticas de memoria máxima.
aculich
44
Perl GANA totalmente en la ofuscación.
Massimo
44
Describir un script de Perl como "corto y críptico" es redundante.
Belmin Fernández
@aculich, con la excepción del script de PowerShell, todas las opciones parecen tomar menos de 0.1 segundos en mi archivo.
Zoredache
0
awk -F"." 's="";{for(i=NF;i>0;i--) {if (i<NF) s=s "." $i; else s=$i}; print s}' <<<filename>>> | sort | awk -F"." 's="";{for(i=NF;i>0;i--) {if (i<NF) s=s "." $i; else s=$i}; print s}'

Lo que esto hace es revertir cada archivo en el nombre de dominio, ordenar y revertir.

Esto realmente ordena la lista de dominios, lexicográficamente basada en cada parte del nombre de dominio, de derecha a izquierda.

La solución inversa ( rev <<<filename>>> | sort | rev) no, lo he intentado.

Mike Rudra
fuente