2012-07-18 16 views
17

Ho un file denominato dominio che contiene alcuni domini. Per esempio:Come utilizzare le variabili di awk nelle espressioni regolari?

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

E ho un altro file chiamato sito che contiene alcuni siti URL e numeri. Ad esempio:

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

Ora ho intenzione di contare il numero di URL di ciascun dominio. Ad esempio: google.com ha 10 + 8. Così ho scritto uno script awk in questo modo:

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; 
     } 
    } 
    } 
} 

Ma il codice if($1 ~/$dom$) non funziona come voglio. Perché la variabile $ dom nell'espressione regolare è stata spiegata letteralmente. Quindi, la prima domanda è:

Esiste un modo per utilizzare la variabile $dom in un'espressione regolare?

Poi, come io sono nuovo alla scrittura di script

Esiste un modo migliore per risolvere il problema che ho?

risposta

15

Innanzitutto, la variabile è dom non $dom - considerano $ come operatore per estrarre il valore del numero di colonna memorizzato nella variabile dom

secondo luogo, awk non interpolare ciò che è tra // - quella è solo una stringa lì dentro.

si desidera che la funzione di match() dove il secondo argomento può essere una stringa che viene trattato come l'espressione regolare:

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

avrei codificare una soluzione come:

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

Apropos tutti coloro che a parlare di come variabili non sono precedute con $, è meglio spiegare (IMO) come $ significa campo in awk, quindi $ dom vorrebbe dire campo qualunque sia il valore di dom. Le variabili in awk vengono utilizzate senza quotazioni e senza $. Non è shell! –

1

Un modo utilizzando un awk script:

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] 
    } 
} 

Esegui come:

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

Risultati:

facebook.com 37 
google.com 18 
+0

Questo approccio non funzionerà se si ottiene un dominio come "first.second.example.com" nel file 'site'. –

+0

@glennjackman, sì, hai ragione. Non l'ho considerato :-( – Steve

1

si vuole chiaramente di leggere il file site una volta, non una volta per ogni voce nel domain. Fissare ciò, tuttavia, è banale.

Allo stesso modo, le variabili in awk (diversi campi $0 .. $9, ecc) non sono precedute da $. In particolare, $dom è il numero del campo identificato dalla variabile dom (in genere, sarà 0 poiché le stringhe del dominio non vengono convertite in nessun altro numero).

Penso che sia necessario trovare un modo per ottenere il dominio dai dati letti dal file site. Non sono sicuro se è necessario gestire siti con domini di paesi come bbc.co.uk e siti nei GTLD (google.com ecc.). Dando per scontato che non si tratta di domini di campagna, è possibile utilizzare questo:

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] 
} 

Nella seconda while ciclo, ci sono NF campi; $NF contiene il conteggio e $1 .. $(NF-1) contiene componenti del dominio. Pertanto, topdom contiene il nome di dominio superiore, che viene quindi utilizzato per indicizzare l'array inizializzato nel primo ciclo.

Visti i dati in questione (meno le linee di punti), l'output è:

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

awk può abbinare contro una variabile se non si utilizzano i marcatori // regex.

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

In questo caso, costruire la regex richiesta come una stringa

regex = dom"$" 

Poi corrispondere contro il regex variabile

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