awk

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
manni33
Beiträge: 1
Registriert: 23.11.2011 20:22:22

awk

Beitrag von manni33 » 23.11.2011 20:51:03

Ich habe eine Datei mit ca 500000 Zeilen.

Die Werte sind Spaltenweise, durch Leerzeichen getrennt.
In der 8. Spalte und in der 12 Spalte sind Angaben die in den unterschiedlichen Zeilen gleich vorkommen.

Diese müssen gezählt werden.

Beispiel

Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Lampen 133
Gebaude Garage 3 4 5 66 777 Giebel 9 100 111 Birnen 133
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Lampen 133
Gebaude Garage 3 4 5 66 777 Giebel 9 100 111 Lampen 133
Gebaude Schuppen 3 4 5 66 777 Dach 9 100 111 Birnen 133
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Birnen 133


Das Ergebnis soll sein:

Dach Lampen 2
Dach Birnen 2
Giebel Birnen 1
Giebel Lampen 1

Ich hoffe mir kann jemand helfen, Danke

Benutzeravatar
GoKi
Beiträge: 2068
Registriert: 04.07.2003 23:08:56
Lizenz eigener Beiträge: MIT Lizenz

Re: awk

Beitrag von GoKi » 23.11.2011 22:58:02

Recht straight-forward in awk (script.awk im folgenden):

Code: Alles auswählen

{
  count[$8, $12]++;
}

END {
  for (e in count) {
    split(e, idx, SUBSEP);
    print idx[1] " " idx[2] " " count[e];
  }
}
Das Sortieren der Einfachheit halber mittels sort über eine Pipe:

Code: Alles auswählen

awk -f script.awk < data.txt | sort -k 3 -n -r
MfG GoKi
:wq

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: awk

Beitrag von Cae » 23.11.2011 23:43:43

Oder mit weniger awk-Gemache:

Code: Alles auswählen

~/manni$ cat data 
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Lampen 133
Gebaude Garage 3 4 5 66 777 Giebel 9 100 111 Birnen 133
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Lampen 133
Gebaude Garage 3 4 5 66 777 Giebel 9 100 111 Lampen 133
Gebaude Schuppen 3 4 5 66 777 Dach 9 100 111 Birnen 133
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Birnen 133
~/manni$ sort data | uniq -c | awk '{ print $9 " " $13 " " $1 }'
Giebel Birnen 1
Giebel Lampen 1
Dach Birnen 1
Dach Birnen 1
Dach Lampen 2
uniq -c ist in dem Fall ganz brauchbar.

Gruß Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
GoKi
Beiträge: 2068
Registriert: 04.07.2003 23:08:56
Lizenz eigener Beiträge: MIT Lizenz

Re: awk

Beitrag von GoKi » 23.11.2011 23:56:59

Aber erfüllt nicht ganz die Anforderungen. Du hast zweimal "Dach Birnen 1" im Ergebnis, da sich die Zeilen in $2 unterscheiden.
MfG GoKi
:wq

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: awk

Beitrag von Cae » 24.11.2011 00:13:19

GoKi hat geschrieben:Aber erfüllt nicht ganz die Anforderungen. Du hast zweimal "Dach Birnen 1" im Ergebnis, da sich die Zeilen in $2 unterscheiden.
Verd***mt, du hast Recht.
Dem kann man ja mit nochmal sort, uniq und awk abhelfen… die Sache wird nur leicht unübersichtlich:

Code: Alles auswählen

~/manni$ cat data 
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Lampen 133
Gebaude Garage 3 4 5 66 777 Giebel 9 100 111 Birnen 133
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Lampen 133
Gebaude Garage 3 4 5 66 777 Giebel 9 100 111 Lampen 133
Gebaude Schuppen 3 4 5 66 777 Dach 9 100 111 Birnen 133
Gebaude Wohnhaus 3 4 5 66 777 Dach 9 100 111 Birnen 133
~/manni$ sort data | uniq -c | awk '{ print $9 " " $13 " " $1 }' | sort | uniq -c | awk '{ print $2 " " $3 " " $1+$4-1 }'
Dach Birnen 2
Dach Lampen 2
Giebel Birnen 1
Giebel Lampen 1
:mrgreen:

Gruß Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
GoKi
Beiträge: 2068
Registriert: 04.07.2003 23:08:56
Lizenz eigener Beiträge: MIT Lizenz

Re: awk

Beitrag von GoKi » 24.11.2011 01:25:31

Alternativ würde sich auch ein

Code: Alles auswählen

cut -d" " -f8,12
am Anfang deiner Pipe anbieten. :-)
MfG GoKi
:wq

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: awk

Beitrag von Meillo » 24.11.2011 08:54:26

Schoen, ein Thread zu awk. :-)

Das ist auch schon alles was ich sagen wollte ...
Use ed once in a while!

rendegast
Beiträge: 15041
Registriert: 27.02.2006 16:50:33
Lizenz eigener Beiträge: MIT Lizenz

Re: awk

Beitrag von rendegast » 24.11.2011 12:35:09

Code: Alles auswählen

$ cat data | awk '{print $8,$12}' | sort | uniq -c         # | awk '{print $2,$3,$1}'
      2 Dach Birnen
      2 Dach Lampen
      1 Giebel Birnen
      1 Giebel Lampen
Das funktioniert auch bei 5.000.000 Zeilen (280MB):

Code: Alles auswählen

$ time awk '{print $8,$12}' data2 | sort | uniq -c
1678320 Dach Birnen
1678320 Dach Lampen
 839160 Giebel Birnen
 839160 Giebel Lampen

real    0m8.105s
user    0m8.757s
sys     0m0.788s
(Grenze freier Speicher?)
aber vielleicht bei sehr, sehr vielen Zeilen auf einzelne Jobs aufteilen?

Code: Alles auswählen

$ cat data | awk '$8=="Dach" && $12=="Birnen"' | wc -l
2
mfg rendegast
-----------------------
Viel Eifer, viel Irrtum; weniger Eifer, weniger Irrtum; kein Eifer, kein Irrtum.
(Lin Yutang "Moment in Peking")

Benutzeravatar
GoKi
Beiträge: 2068
Registriert: 04.07.2003 23:08:56
Lizenz eigener Beiträge: MIT Lizenz

Re: awk

Beitrag von GoKi » 24.11.2011 13:56:27

Naja, ab einer gewissen Menge an Daten ist das Sortieren dieser 5.000.000 Zeilen auch nicht zu unterschätzen, sowohl bzgl. Zeit als auch Speicherbedarf.
Ein kurzer Test ergab folgendes (data hat 5.000.006 Zeilen):

Code: Alles auswählen

$ wc -l data 
5000006 data
$ time awk '{print $8,$12}' data | sort | $(uniq -c >/dev/null)
real	0m8.345s
user	0m8.617s
sys	0m0.276s

$ time cut -d" " -f8,12 data | sort | $(uniq -c >/dev/null)
real	0m4.902s
user	0m5.268s
sys	0m0.176s

$ time awk -f script.awk < data | $(sort -k 3 -n -r >/dev/null)
real	0m3.572s
user	0m3.536s
sys	0m0.024s
Wir sehen da ein paar bekannte Effekte, z.B. cut ist schneller als awk, wenn man nur ein paar Felder extrahieren will.
Also ich bleib beim awk Script, mit mawk statt gawk ist's noch schneller.
MfG GoKi
:wq

Benutzeravatar
ThorstenS
Beiträge: 2875
Registriert: 24.04.2004 15:33:31

Re: awk

Beitrag von ThorstenS » 24.11.2011 14:08:28

Von der Lesbarkeit finde ich das hier am Schönsten: (auch wenn die awk Variante schneller ist)

Code: Alles auswählen

cut -d " " -f8,12 data |sort -k2 | uniq -c | column -t
2  Dach    Birnen
1  Giebel  Birnen
2  Dach    Lampen
1  Giebel  Lampen

Antworten