2012-07-18 40 views
17

Tengo un archivo llamado dominio que contiene algunos dominios. Por ejemplo:¿Cómo usar las variables awk en expresiones regulares?

google.com 
facebook.com 
... 
yahoo.com 

Y tengo otro archivo llamado sitio que contiene algunas de las URL y los números de los sitios. Por ejemplo:

image.google.com 10 
map.google.com  8 
... 
photo.facebook.com 22 
game.facebook.com 15 
.. 

Ahora voy a contar el número de url que tiene cada dominio. Por ejemplo: google.com tiene 10 + 8. Así que escribí un script awk como esto:

BEGIN{ 
    while(getline dom < "./domain" > 0) { 
    domain[dom]=0; 
    } 
    for(dom in domain) { 
    while(getline < "./site" > 0) { 
     if($1 ~/$dom$) #if $1 end with $dom { 
     domain[dom]+=$2; 
     } 
    } 
    } 
} 

Pero el código if($1 ~/$dom$) no funciona como yo quiero. Porque la variable $ dom en la expresión regular se explicó literalmente. Entonces, la primera pregunta es:

¿Hay alguna forma de usar la variable $dom en una expresión regular?

Entonces, como soy nuevo en la escritura de la escritura

¿Hay alguna forma mejor para resolver el problema que tengo?

Respuesta

15

En primer lugar, la variable es dom no $dom - $ consideran como un operador para extraer el valor de la columna número almacenado en la variable dom

En segundo lugar, awk no va a interpolar lo que hay entre // - eso es solo una cadena ahí.

desea que la función match() en el que el segundo argumento puede ser una cadena que se considere la expresión regular:

if (match($1, dom "$")) {...} 

Me codificar una solución como:

awk ' 
    FNR == NR {domain[$1] = 0; next} 
    { 
    for (dom in domain) { 
     if (match($1, dom "$")) { 
     domain[dom] += $2 
     break 
     } 
    } 
    } 
    END {for (dom in domain) {print dom, domain[dom]}} 
' domain site 
+0

A propósito todos aquellos hablando de cómo las variables no tienen el prefijo con $, se explica mejor (IMO) como $ significa campo en awk, por lo que $ dom significa campo cualquiera que sea el valor de dom. Las variables en awk se usan sin comillas y sin $. ¡No es concha! –

1

Una forma utilizando una awk guión:

BEGIN { 
    FS = "[. ]" 
    OFS = "." 
} 

FNR == NR { 
    domain[$1] = $0 
    next 
} 

FNR < NR { 
    if ($2 in domain) { 
     for (i = 2; i < NF; i++) { 
      if ($i != "") { 
       line = (line ? line OFS : "") $i 
      } 
     } 
     total[line] += $NF 
     line = "" 
    } 
} 

END { 
    for (i in total) { 
     printf "%s\t%s\n", i, total[i] 
    } 
} 

Ejecutar como:

awk -f script.awk domain.txt site.txt 

Resultados:

facebook.com 37 
google.com 18 
+0

Este enfoque no funcionará si obtiene un dominio como "first.second.example.com" en el archivo 'site'. –

+0

@glennjackman, sí, estás en lo cierto. No lo consideré :-( – Steve

1

claramente desea leer el archivo site una vez, ni una sola vez por cada entrada en domain. Reparar eso, sin embargo, es trivial.

Igualmente, las variables en awk (distintos campos $0 .. $9, etc.) no tienen el prefijo $. En particular, $dom es el número de campo identificado por la variable dom (típicamente, va a ser 0 ya que las cadenas de dominio no se convierten a ningún otro número).

Creo que debe encontrar una forma de obtener el dominio de los datos leídos del archivo site. No estoy seguro si necesita tratar con sitios con dominios de país como bbc.co.uk, así como sitios en los GTLD (google.com, etc.). Suponiendo que no se trata de dominios de país, puede utilizar esto:

BEGIN { 
    while (getline dom < "./domain" > 0) domain[dom] = 0 
    FS = "[ .]+" 
    while (getline < "./site" > 0) 
    { 
     topdom = $(NF-2) "." $(NF-1) 
     domain[topdom] += $NF   
    } 
    for (dom in domain) print dom " " domain[dom] 
} 

En el segundo bucle while, hay NF campos; $NF contiene el recuento y $1 .. $(NF-1) contienen componentes del dominio. Por lo tanto, topdom termina conteniendo el nombre de dominio superior, que luego se usa para indexar en la matriz inicializada en el primer ciclo.

Teniendo en cuenta los datos de la pregunta (menos las líneas de puntos), la salida es:

yahoo.com 0 
facebook.com 37 
google.com 18 
17

awk pueden igualar en contra de una variable si no utiliza los marcadores // de expresiones regulares.

if ($0 ~ regex){ print $0; }

En este caso, aumente la expresión regular requerida como una cadena

regex = dom"$" 

Luego partido contra el regex variables

if ($1 ~ regex) { 
    domain[dom]+=$2; 
} 
Cuestiones relacionadas