2012-07-18 7 views
17

Ich habe eine Datei namens Domäne, die einige Domänen enthält. Zum Beispiel:Wie verwendet man awk-Variablen in regulären Ausdrücken?

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

Und ich habe eine andere Datei Website genannt, die einige Websites, URLs und Zahlen enthält. Zum Beispiel:

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

Jetzt werde ich die URL-Nummer jeder Domäne zählen. Zum Beispiel: google.com hat 10 + 8. Also schrieb ich ein awk-Skript wie folgt aus:

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

Aber der Code if($1 ~/$dom$) läuft nicht wie ich will. Weil die Variable $ dom im regulären Ausdruck wörtlich erklärt wurde. Also, die erste Frage lautet:

Gibt es eine Möglichkeit, Variable $dom in einem regulären Ausdruck zu verwenden?

Dann, als ich

zu schreiben Skript neu bin

Gibt es einen besseren Weg, um das Problem, das ich habe zu lösen?

Antwort

15

Zunächst einmal ist die Variable dom nicht $dom - $ als Operator betrachten den Wert der Spaltennummer in der Variablen dom

Zweitens gespeichert zu extrahieren, awk wird nicht interpoliert, was zwischen // ist - das ist nur eine Schnur drin.

Sie wollen die match() Funktion, wo das zweite Argument eine Zeichenfolge sein kann, die als regulärer Ausdruck behandelt wird:

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

propos alle reden, wie Variablen nicht Präfix mit $, es ist besser erklärt (IMO) als $ bedeutet Feld in awk, so $ dom würde Feld bedeuten, was auch immer der Wert von dom ist. Variablen in awk werden ohne Anführungszeichen und ohne $ verwendet. Es ist keine Shell! –

1

Eine Möglichkeit, mit ein:

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

ich eine Lösung wie Code würde awk Skript:

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

Run like:

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

Ergebnisse:

facebook.com 37 
google.com 18 
+0

Dieser Ansatz wird nicht funktionieren, wenn Sie eine Domäne wie "first.second.example.com" in der 'site'-Datei erhalten. –

+0

@Glennjackman, ja du bist richtig. Das habe ich nicht berücksichtigt :-( – Steve

1

Sie wollen klar, sobald die site-Datei zu lesen, nicht einmal pro Eintrag in domain. Das zu beheben ist jedoch trivial.

Ebenso Variablen in awk (ausgenommen Felder $0 .. $9, usw.) sind nicht mit $ vorangestellt. Insbesondere ist $dom die Feldnummer, die durch die Variable dom identifiziert wird (normalerweise wird das 0 sein, da Domänenstrings nicht in eine andere Zahl konvertiert werden).

Ich denke, Sie müssen einen Weg finden, um die Domain aus den Daten aus der site Datei gelesen zu bekommen. Ich bin mir nicht sicher, ob Sie mit Websites mit Länderdomänen wie bbc.co.uk sowie Websites in den GTLDs (google.com etc) umgehen müssen. Angenommen, Sie sind mit Länderdomains nicht zu tun haben, können Sie diese verwenden:

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

In der zweiten while Schleife gibt es NF Felder; $NF enthält die Anzahl und $1 .. $(NF-1) enthalten Komponenten der Domäne. So endet topdom mit dem obersten Domänennamen, der dann zum Indizieren in das in der ersten Schleife initialisierte Array verwendet wird.

die Daten in der Frage Given (minus den Linien von Punkten), die Ausgabe ist:

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

awk gegen eine Variable übereinstimmen, wenn Sie die nicht // regex Marker verwenden.

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

In diesem Fall

die erforderliche regex als String aufbauen
regex = dom"$" 

Dann passen gegen die regex Variable

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