Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfassen

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Master Mayhem
Beiträge: 582
Registriert: 04.04.2004 00:04:46
Lizenz eigener Beiträge: neue BSD Lizenz

Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfassen

Beitrag von Master Mayhem » 07.05.2010 20:38:48

Hallo zusammen,

will ne kleine Inventur der Client Hardware machen, wobei mich eigentlich nur CPU und RAM interessiert. Dazu habe ich per login Script alle Clients (WinXP Clients) ein dxdiag ausführen lassen und das in Unterordner, die den jeweiligen Hostnamen erhalten auf dem server abgelegt. Mittels ein paar Zeilen mit grep und sed hab ich das ganze schon auf folgendes reduziert:

Code: Alles auswählen

HOSTNAME1;Processor;Intel(R) Pentium(R) 4 CPU 3.20GHz (2 CPUs)
HOSTNAME1;Memory;502MB RAM
HOSTNAME2;Processor;Intel(R) Pentium(R) 4 CPU 3.20GHz (2 CPUs)
HOSTNAME2;Memory;502MB RAM
HOSTNAME3;Processor;Intel(R) Pentium(R) 4 CPU 3.20GHz (2 CPUs)
HOSTNAME3;Memory;1014MB RAM
HOSTNAME4;Processor;Intel(R) Xeon(R) CPU           L5410  @ 2.33GHz
HOSTNAME4;Memory;1024MB RAM
HOSTNAME5;Processor;Intel(R) Core(TM) Duo CPU      T2500  @ 2.00GHz (2 CPUs)
HOSTNAME5;Memory;1022MB RAM
...usw.
Ich hätte es aber gerne so formatiert:

Code: Alles auswählen

HOSTNAME1;Processor;Intel(R) Pentium(R) 4 CPU 3.20GHz (2 CPUs);Memory;502MB RAM
HOSTNAME2;Processor;Intel(R) Pentium(R) 4 CPU 3.20GHz (2 CPUs);Memory;502MB RAM
HOSTNAME3;Processor;Intel(R) Pentium(R) 4 CPU 3.20GHz (2 CPUs);Memory;1014MB RAM
HOSTNAME4;Processor;Intel(R) Xeon(R) CPU           L5410  @ 2.33GHz;Memory;1024MB RAM
HOSTNAME5;Processor;Intel(R) Core(TM) Duo CPU      T2500  @ 2.00GHz (2 CPUs);Memory;1022MB RAM
Bzw. Processor und Memory würd ich auch noch entfernen per sed, oder awk und die erste Zeile soll das enthalten:

Code: Alles auswählen

Hostname;Processor;Memory
Das Ziel ist ne .csv zu bekommen, die pro Zeile beide Infos enthält und nicht zwei Zeilen je Hostname. Ich könnte auch erstmal in zwei temporäre Dateien schreiben, in eine die CPU und die andere die RAM und dann zusammenfassen. Hab noch nicht so viel Erfahrung mit sed und awk, hab aber das gefühl, dass das ganz einfach damit geht, ohne lange Schleifen bauen zu müssen. Jemand ne Idee?

Hier übrigens das kurze Script mit dem ich die dxdiag infos auswerte, um zu der o.g. auswertung zu kommen:
(ja ich muss den Pfad noch sauber auf ne Variable legen, um mir das cd und das */* zu sparen, ist ja nur ein Entwurf):

Code: Alles auswählen

#!/bin/sh
cd /srv/share/daten/common/clientinfos/ && rm *.csv
grep -e Processor: -e Memory: */* |\
sed -e '/Display/,/HW/d' |\
sed -e 's/\/dxdiag.txt:/:/' |\
sed -e 's/             / /' |\
sed -e 's/          / /' |\
sed -e 's/: /;/g' > auswertung.csv
egrep '\<[0-9]{2,3}\MB\>' auswertung.csv > lowRAM.csv
egrep '\<1[0-9]{2,3}\MB\>' auswertung.csv > mediumRAM.csv
egrep '\<[2-9][0-9][0-9]{2,2}\MB\>' auswertung.csv > highRAM.csv
mfg tyler

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

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Meillo » 07.05.2010 21:37:53

Hier mal ein kleiner Ansatz auf den du aufbauen kannst. Ich habe gerade leider nicht mehr Zeit für was Ausführlicheres.

Code: Alles auswählen

awk -F';' '{if ($1==last) {$1=""; print } else {last=$1; printf $0}}'
Use ed once in a while!

Benutzeravatar
Master Mayhem
Beiträge: 582
Registriert: 04.04.2004 00:04:46
Lizenz eigener Beiträge: neue BSD Lizenz

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Master Mayhem » 10.05.2010 21:34:12

THX!

Das wars und zwar c&p...nur hab ich noch fast 2h in der Doku von awk gelesen zum printf Befehlt, weil die Ausgabe zuerst voll krüppelig aussah. Erst als ich den Gegentest mit ein paar Datensätzen, die ich mit c&p in eine Datei eingefügt habe musste ich dann festellen, dass das nur an dem Zeilenendzeichen von Windoof lag, denn ich lass die Dateien ja per cmd auf ein samba share kopieren und da kommt dann das windoof Zeilenendzeichen an. more und cat stört das nicht bei der Ausgabe (außer das steht mitten in der Zeile und nicht am ende), mcedit und vi haben verschieden Darstellungen davon:

Code: Alles auswählen

sed -e 's/^M/ /'
in meinem vi wirds blau dargestellt, im mcedit ist das nur ein ^ auf schwarzem Hintergrund mit einem folgendem Leerzeichen.

Dafür hab ich aber einiges über den printf Befehl von awk gelernt...war aber trotzdem zu faul die erste Zeile (Hostname;Prozessor;RAM) und die restliche Ausgabe per awk zu schreiben...

Hier der komplette Code:

Code: Alles auswählen

#!/bin/sh
pfad='/srv/share/daten/common/clientinfos'
rm $pfad/*.csv
echo "Hostname;Prozessor;RAM" | tee $pfad/auswertung.csv $pfad/lowRAM.csv $pfad/mediumRAM.csv $pfad/highRAM.csv
grep -e Processor: -e Memory: -m2 */* |\
sed -e 's/\/dxdiag.txt:/:/' |\
sed -e 's/             / /' |\
sed -e 's/          / /' |\
sed -e 's/     / /' |\
sed -e 's/  / /' |\
sed -e 's/: /;/g' |\
sed -e 's/^M/ /' |\
awk -F';' '{if ($1==last) {$1=""; print } else {last=$1; printf $0}}' |\
sed -e 's/;Processor;/;/' |\
sed -e 's/ RAM //' |\
sed -e 's/  Memory /;/' >> $pfad/auswertung.csv
egrep '\<[0-9]{2,3}\MB\>' $pfad/auswertung.csv >> $pfad/lowRAM.csv
egrep '\<1[0-9]{2,3}\MB\>' $pfad/auswertung.csv >> $pfad/mediumRAM.csv
egrep '\<[2-9][0-9]{3,3}\MB\>' $pfad/auswertung.csv >> $pfad/highRAM.csv
p.s. für so ein hingerotztes Stück shellscript lohnt es eigentlich nicht den pfad auf ne Variable zu legen, war vorher mit nem cd viel kürzer und zu pflegen gibts da nicht viel. Hab gestern mit dem Lama Buch angefangen Perl zu lernen, das wird meine erste Aktion sein, wenn ich damit fertig bin, das shellscript und die windoof cmd beide in Perl umzusetzen.

Denke ich hab sogar deine Schleife verstanden, sowas in der Art hatte ich auch schon im Kopf, nur nicht in einer Zeile in ner Klammer von awk, ich hatte echt wilde Konstrukte im Kopf, wo ich mir sicher war, dass das leichter geht - nochmal danke!

mfg tyler

Benutzeravatar
Duff
Beiträge: 6321
Registriert: 22.03.2005 14:36:03
Wohnort: /home/duff

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Duff » 11.05.2010 08:17:20

Meillo hat geschrieben:Hier mal ein kleiner Ansatz auf den du aufbauen kannst. Ich habe gerade leider nicht mehr Zeit für was Ausführlicheres.

Code: Alles auswählen

awk -F';' '{if ($1==last) {$1=""; print } else {last=$1; printf $0}}'
Habe mal wieder Probleme, diese Zeile zu verstehen.
Kannst du dies eventuell nochmals erklären? (Bitte)
Oh, yeah!

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

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Meillo » 11.05.2010 12:17:20

Duff hat geschrieben:
Meillo hat geschrieben:Hier mal ein kleiner Ansatz auf den du aufbauen kannst. Ich habe gerade leider nicht mehr Zeit für was Ausführlicheres.

Code: Alles auswählen

awk -F';' '{if ($1==last) {$1=""; print } else {last=$1; printf $0}}'
Habe mal wieder Probleme, diese Zeile zu verstehen.
Kannst du dies eventuell nochmals erklären? (Bitte)
Klar. ;-)


Es sollen aufeinander folgende Zeilen die mit dem gleichen Hostname anfangen zusammengehängt werden.
Der Hostname ist mit einem Strichpunkt vom Rest der Zeile getrennt.

Durch -F';' setze ich den Feldtrenner auf den Strichpunkt und habe den Hostname somit immer in $1.

Für jede Zeile wird geprüft ob der Hostname (also $1) gleich der Variable last ist:
- Falls ja, wird $1 (also der Hostname) entfernt (d.h. die aktuelle Zeile wird verändert), und sie danach ausgegeben (mit Newline am Ende).
- Falls nein, merken wir uns den Hostname in der Variable last, und geben die Zeile ohne Newline am Ende aus.

Anmerkung:
- In awk sind Variablen automatisch mit "" bzw. 0 initialisiert; das betrifft hier die Variable last.
- Dieses Programm funktioniert nur wenn es maximal zwei aufeinanderfolgende Zeilen für einen Hostname sind. Wenn mehrere vorkommen können muss man es ein bisschen umbauen.
Use ed once in a while!

Benutzeravatar
Duff
Beiträge: 6321
Registriert: 22.03.2005 14:36:03
Wohnort: /home/duff

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Duff » 11.05.2010 13:29:02

Danke für die (wie immer) gute und verständliche Erklärung!
Oh, yeah!

Benutzeravatar
Master Mayhem
Beiträge: 582
Registriert: 04.04.2004 00:04:46
Lizenz eigener Beiträge: neue BSD Lizenz

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Master Mayhem » 11.05.2010 17:52:47

Meillo hat geschrieben:[
- Dieses Programm funktioniert nur wenn es maximal zwei aufeinanderfolgende Zeilen für einen Hostname sind. Wenn mehrere vorkommen können muss man es ein bisschen umbauen.
Oh man, wieso hast du das gesagt, jetzt bin ich neugierig geworden und wollte das umsetzten, egal ob der Hostname jetzt 1 mal, oder 100 mal hintereinander vorkommt. Mit if...else hab ich da keine chance gesehen (die Entscheidung wann die erfüllte Bedingung mit Newline ausgibt und wann ohne Newline bekomm ich nicht hin mit nem if..else, denn ab dem 2. Durchlauf ist das ja immer wahr und er macht nur noch {$1=""; print } bis sich der Hostname ändert), daher hab ich es mit while und do...while versucht komm aber kein Stück weiter. Mit dem switch statement seh ich noch ne Chance, aber da bin ich mir nicht sicher, wie ich überprüfe, ob mein gawk das kann.

Falls du nochmal Zeit hättest mir die Lösung aufm Silbertablett zu präsentieren, wäre das sehr nett (und ich ärger mich voll fragen zu müssen, wie ich die Abfrage baue weiß ich wohl, ich bekomm es logisch nicht hin).

mfg tyler

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

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Meillo » 11.05.2010 22:30:32

Master Mayhem hat geschrieben:
Meillo hat geschrieben: - Dieses Programm funktioniert nur wenn es maximal zwei aufeinanderfolgende Zeilen für einen Hostname sind. Wenn mehrere vorkommen können muss man es ein bisschen umbauen.
Oh man, wieso hast du das gesagt, jetzt bin ich neugierig geworden und wollte das umsetzten, egal ob der Hostname jetzt 1 mal, oder 100 mal hintereinander vorkommt.
Hehe. :twisted:
Mit if...else hab ich da keine chance gesehen (die Entscheidung wann die erfüllte Bedingung mit Newline ausgibt und wann ohne Newline bekomm ich nicht hin mit nem if..else, denn ab dem 2. Durchlauf ist das ja immer wahr und er macht nur noch {$1=""; print } bis sich der Hostname ändert), daher hab ich es mit while und do...while versucht komm aber kein Stück weiter. Mit dem switch statement seh ich noch ne Chance, aber da bin ich mir nicht sicher, wie ich überprüfe, ob mein gawk das kann.

Falls du nochmal Zeit hättest mir die Lösung aufm Silbertablett zu präsentieren, wäre das sehr nett (und ich ärger mich voll fragen zu müssen, wie ich die Abfrage baue weiß ich wohl, ich bekomm es logisch nicht hin).
So groß müssen die Änderungen gar nicht sein. Es bedarf nur eines einzeiligen Blockes mit Bedingung und einer kleinen Änderung im bestehenden Code.

Ich verrate das Ergebnis noch nicht, aber den Trick:

Man weiß nicht ob die nächsten Zeilen auch an die aktuelle Zeile angefügt werden sollen. Man weiß das erst wenn man auf eine Zeile trifft die nicht mehr angefügt werden soll. Deshalb sollte man das Newlinezeichen genau zu dem Zeitpunkt ausgeben, nämlich vor der Zeile die nicht mehr hinten hin gehört. Sonst lässt man alle Zeilenumbrüche weg (printf statt print). Dann muss man nur noch einen Extremfall abfangen, nämlich die erste Zeile, aber das geht mit einer Bedinung ganz einfach.

Jetzt versucht euch mal selbst.
Use ed once in a while!

Benutzeravatar
Master Mayhem
Beiträge: 582
Registriert: 04.04.2004 00:04:46
Lizenz eigener Beiträge: neue BSD Lizenz

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Master Mayhem » 12.05.2010 18:47:48

Manchmal hilft ne Nacht drüber schlafen....beim Aufwachen hatte ich die Antwort: noch eine Variable einführen, um die aktuell bearbeitete Zeile zu speichern und erst dann auszugeben, wenn ich weiß, ob \n oder nicht. Das war immer mein Problem, wenn ich weiß, dass $1 sich geändert hat hab ich die letzte Zeile ja schon ausgegeben und es ist zu spät um sich nachträglich zu entscheiden, ob \n oder nicht.

Gestern abend hab ich noch überlegt, ob ich Perl lernen mir nicht spare, wenn ich es handwerklich kann, aber die logik nicht auf die Reihe bekomme, kann ich damit nix anfangen.

Man müsste es noch schön formatieren und die Ausgabe ist auch noch nicht schön, aber die logik müsste stimmen:
(das ist eine Zeile, auch wenn die meisten es hier mit Zeilenumbruch sehen werden, formatierung fehlt halt gänzlich)

Code: Alles auswählen

awk -F';' 'BEGIN {lhost=$1; lline=$0} {if ($1==lhost) {printf(lline); lline=$0 } else {lhost=$1; print lline; lline=$0}} END {print lline}'
Bestimmt geht das noch eleganter, denn ich brauch auch für die letzte Zeile noch nen END Block, nicht nur den BEGIN Block für die erste Zeile.

Danke, dass du mir die Lösung NICHT auf dem Silbertablett präsentiert hast, so hab ich das awk Handbuch nochmal gründlich gelesen und mehr dabei gelernt. Hier gibts übrigens ein ganz gutes awk Tutorial:
http://www.vectorsite.net/tsawk.html

mfg tyler

p.s.: jetzt sag bitte nicht, dass das falsch ist und liefer direkt nen Testdatensatz, bei dem das in die Hose geht, bei meinen Testdatensätzen wars immer OK und ich bin etwas stolz darauf

***edit***
hmm...wunder mich grade etwas, dass er mir die erste Zeile nicht zweimal ausgibt, wegen dem lline=$0 im BEGIN Block, es geht auf jeden Fall auch ohne und dann ist mir auch klar, dass die erste Zeile nur einmal ausgegeben wird, beim ersten Durchlauf ist lline mit "" (leerer String) gefüllt, macht aber kein \n, also de facto kein output, und danach füllt die Schleife lline immer korrekt.

Code: Alles auswählen

awk -F';' 'BEGIN {lhost=$1} {if ($1==lhost) {printf(lline); lline=$0 } else {lhost=$1; print lline; lline=$0}} END {print lline}'
Wieso gibt er mir bei dem code oben die erste Zeile nicht zweimal aus? Darf ich im Beginn Block keine zwei Variablen füllen, ist die Syntax falsch (glaub ich fast nicht awk meckert doch sofort), oder kann ich aus derselben Zeile kein $1 und $0 auslesen?

Benutzeravatar
Duff
Beiträge: 6321
Registriert: 22.03.2005 14:36:03
Wohnort: /home/duff

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Duff » 13.05.2010 11:21:01

Ich habe es auch mal probiert, aber bin zu keinem zufriedenstellendem Resultat gekommen.

Wie sieht denn dein Input-File aus und der gewünschte Output?
Oh, yeah!

Benutzeravatar
Master Mayhem
Beiträge: 582
Registriert: 04.04.2004 00:04:46
Lizenz eigener Beiträge: neue BSD Lizenz

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Master Mayhem » 13.05.2010 16:42:50

Wo kommst du nicht zu dem gewünschten Ergebnis? Du hast nen Testfile, wo mein Weg in die Hose geht, oder du hast es auf einem anderen Weg versucht, der nicht zuverlässig funktioniert?

Code: Alles auswählen

tyler@wolfenstein:~/awk$ more testdatensatz5x5
a;1p;1q;1r
a;2p;2q;2r
a;3p;3q;3r
a;4p;4q;4r
a;5p;5q;5r
b;6p;6q;6r
b;7p;7q;7r
b;8p;8q;8r
b;9p;9q;9r
b;10p;10q;10r
c;11p;11q;11r
c;12p;12q;12r
c;13p;13q;13r
c;14p;14q;14r
c;15p;15q;15r
d;16p;16q;16r
d;17p;17q;17r
d;18p;18q;18r
d;19p;19q;19r
d;20p;20q;20r
e;21p;21q;21r
e;22p;22q;22r
e;23p;23q;23r
e;24p;24q;24r
e;25p;25q;25r
tyler@wolfenstein:~/awk$ awk -F';' 'BEGIN {lhost=$1} {if ($1==lhost) {printf(lline); lline=$0 } else {lhost=$1; print lline; lline=$0}} END {print lline}' testdatensatz5x5 | more

a;1p;1q;1ra;2p;2q;2ra;3p;3q;3ra;4p;4q;4ra;5p;5q;5r
b;6p;6q;6rb;7p;7q;7rb;8p;8q;8rb;9p;9q;9rb;10p;10q;10r
c;11p;11q;11rc;12p;12q;12rc;13p;13q;13rc;14p;14q;14rc;15p;15q;15r
d;16p;16q;16rd;17p;17q;17rd;18p;18q;18rd;19p;19q;19rd;20p;20q;20r
e;21p;21q;21re;22p;22q;22re;23p;23q;23re;24p;24q;24re;25p;25q;25r
tyler@wolfenstein:~/awk$
Hab auch schonmal einfach ne Zeile, die mit x anfängt dazwischen gesetzt, kommt der mit klar. Solange die nächste Zeile mit demselben String anfängt, wie die letzte Zeile wird alles in einer Zeile ausgegeben, erst wenn er erkennt, dass ein anderer Anfangsstring kommt gibts nen Zeilenumbruch. Wenn ich mit grep suche und mir die Datei angeben lasse in der er den Begriff gefunden hat und ich nach mehreren Begriffen in einem grep Befehl suche, bekomme ich ja genau so eine ausgabe, die dann aber zu ner Tabelle im .csv Format werden soll.

Code: Alles auswählen

awk -F';' 'BEGIN {lhost=$1} {if ($1==lhost) {printf(lline ";" ); lline=$0 } else {lhost=$1; print lline; lline=$0}} END {print lline}'
So hab ich schonmal das Feldtrennzeichen ; dazwischen, aber der Hostname kommt mehrfach vor in einer Zeile des ouptput files. Da ich die letzte zeile ja immer erst ausgebe, wenn ich die aktuelle bearbeite kann ich aber auch nicht durchgehend $1 entfernen, dann steht das gar nicht mehr dabei im output. Da müsste ich jetzt noch einen drüberziehen, der mir bis aus das erste Vorkommen eines Begriffes alle weiteren entfernt, wenns nicht regelmäßig ist. Wenns regelmäßig ist, kann ich einfach bestimmte Felder entfernen.

Zuerst war ich dabei immer wenn er erkennt, das $1!=lhost (!= ungleich) printf(\n $0) auzugeben und sonst immer printf($0) aber da stimmt irgendwas mit der syntax nicht von printf(\n $0). \n ist beim awk printf() dasselbe wie bei perl, also newline. Das löst aber auch leider nicht, dass er nur beim ersten mal $1 ausgeben soll und bei den weiteren dann nicht mehr, bis sich $1 ändert. Denke da brauch ich wirklich noch einen durchlauf und muss mir noch eine nette Schleife ausdenken.

mfg tyler

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

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Meillo » 13.05.2010 17:03:56

Master Mayhem hat geschrieben:Manchmal hilft ne Nacht drüber schlafen....beim Aufwachen hatte ich die Antwort: noch eine Variable einführen, um die aktuell bearbeitete Zeile zu speichern und erst dann auszugeben, wenn ich weiß, ob \n oder nicht. Das war immer mein Problem, wenn ich weiß, dass $1 sich geändert hat hab ich die letzte Zeile ja schon ausgegeben und es ist zu spät um sich nachträglich zu entscheiden, ob \n oder nicht.
Du kannst die Zeilen schon immer ausgeben, nur das Newline-Zeichen nicht. Sonst ist der Ansatz aber genau das was ich meine.
Gestern abend hab ich noch überlegt, ob ich Perl lernen mir nicht spare, wenn ich es handwerklich kann, aber die logik nicht auf die Reihe bekomme, kann ich damit nix anfangen.
Eine Sprache zu lernen bringt einen fast immer weiter. Aber es stimmt natürlich, dass nicht das kennen einer weiteren Sprache die Probleme löst.
Man müsste es noch schön formatieren und die Ausgabe ist auch noch nicht schön, aber die logik müsste stimmen:
(das ist eine Zeile, auch wenn die meisten es hier mit Zeilenumbruch sehen werden, formatierung fehlt halt gänzlich)

Code: Alles auswählen

awk -F';' 'BEGIN {lhost=$1; lline=$0} {if ($1==lhost) {printf(lline); lline=$0 } else {lhost=$1; print lline; lline=$0}} END {print lline}'
In BEGIN-Blöcken ist noch keine Zeile eingelesen. Somit sind die automatischen Feldvariablen $1, $2, ..., und $0 nicht definiert. Der BEGIN-Block macht hier also nichts und kann weggelassen werden.

Die Ausgabe sieht nicht ganz schlecht aus. Der Hostname wird in den angehängten Zeilen nicht entfernt und erscheint somit mehrmals in der Zeile. Das kannst du mit der Zuweisung $1="" an der richtigen Stelle lösen.

Am Anfang wird eine leere Zeile ausgegeben. Das kann durch eine Bedingung abgestellt werden.
Bestimmt geht das noch eleganter, denn ich brauch auch für die letzte Zeile noch nen END Block, nicht nur den BEGIN Block für die erste Zeile.
Wie ich oben beschrieben habe, behandelt der BEGIN-Block *nicht* die erste Zeile. Wenn du die erste Zeile bearbeiten willst, dann brauchst du so einen Block:

Code: Alles auswählen

NR==1 {...}
Danke, dass du mir die Lösung NICHT auf dem Silbertablett präsentiert hast, so hab ich das awk Handbuch nochmal gründlich gelesen und mehr dabei gelernt. Hier gibts übrigens ein ganz gutes awk Tutorial:
http://www.vectorsite.net/tsawk.html
Diese Seite kannte ich noch nicht. Ich finde jedoch, dass die Manpage zu awk sehr gut ist. Ansonsten habe ich hier noch ``sed & awk ge-packt'' von Stephan Thesing das erstklassig ist.
hmm...wunder mich grade etwas, dass er mir die erste Zeile nicht zweimal ausgibt, wegen dem lline=$0 im BEGIN Block, es geht auf jeden Fall auch ohne und dann ist mir auch klar, dass die erste Zeile nur einmal ausgegeben wird, beim ersten Durchlauf ist lline mit "" (leerer String) gefüllt, macht aber kein \n,
Doch, genau das macht er.

Code: Alles auswählen

awk -F';' 'BEGIN {lhost=$1} {if ($1==lhost) {printf(lline); lline=$0 } else {lhost=$1; print lline; lline=$0}} END {print lline}'
Wieso gibt er mir bei dem code oben die erste Zeile nicht zweimal aus?
Du hast doch für alle Zeilen der Datei (außer der letzten) nur ein print bzw. printf, nämlich entweder das eine oder das andere. Also wird *pro* Zeile auch nur einmal ausgegeben, und zwar immer die vorherige (aus lline).

In der ersten Zeile ist lline aber leer, deshalb wird da eine Leerzeile ausgegeben.

(In der letzten Zeile wird die vorletzte ausgegeben; die letzte Zeile wird im END-Block ausgegeben.)
Darf ich im Beginn Block keine zwei Variablen füllen, ist die Syntax falsch (glaub ich fast nicht awk meckert doch sofort), oder kann ich aus derselben Zeile kein $1 und $0 auslesen?
Zu dem Zeitpunkt an dem der BEGIN-Block abgearbeitet wird, wurde noch keine Zeile eingelesen, deshalb sind $0, $1, ... noch nicht gesetzt.
Use ed once in a while!

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

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Meillo » 13.05.2010 17:08:29

Master Mayhem hat geschrieben: Zuerst war ich dabei immer wenn er erkennt, das $1!=lhost (!= ungleich) printf(\n $0) auzugeben und sonst immer printf($0) aber da stimmt irgendwas mit der syntax nicht von printf(\n $0).
$0 ist eine Variable. \n ist ein Zeichen. Ein Zeichen ist Teil eines Strings. Also: printf("\n" $0);
Das löst aber auch leider nicht, dass er nur beim ersten mal $1 ausgeben soll und bei den weiteren dann nicht mehr, bis sich $1 ändert.
Man kann die Felder der aktuellen Zeile verändern indem man ihnen was zuweist: $1 = "foo"
Use ed once in a while!

Benutzeravatar
Master Mayhem
Beiträge: 582
Registriert: 04.04.2004 00:04:46
Lizenz eigener Beiträge: neue BSD Lizenz

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Master Mayhem » 13.05.2010 19:48:53

also so:

Code: Alles auswählen

tyler@wolfenstein:~/awk$ awk -F';' 'BEGIN {lline="hostname;prozessor;RAM"} {if ($1==lhost) {printf(lline ";" ); lline=($2 ";" $3 ";" $4) } else {lhost=$1; print lline; lline=$0}} END {print lline}' testdatensatz5x5 | more
hostname;prozessor;RAM
a;1p;1q;1r;2p;2q;2r;3p;3q;3r;4p;4q;4r;5p;5q;5r
b;6p;6q;6r;7p;7q;7r;8p;8q;8r;9p;9q;9r;10p;10q;10r
c;11p;11q;11r;12p;12q;12r;13p;13q;13r;14p;14q;14r;15p;15q;15r
d;16p;16q;16r;17p;17q;17r;18p;18q;18r;19p;19q;19r;20p;20q;20r
e;21p;21q;21r;22p;22q;22r;23p;23q;23r;24p;24q;24r;25p;25q;25r
tyler@wolfenstein:~/awk$
oder so:

Code: Alles auswählen

tyler@wolfenstein:~/awk$ awk -F';' 'BEGIN {printf("hostname;prozessor;RAM")} {if ($1==lhost) {printf($2 ";" $3 ";" $4 ";")} else {lhost=$1; printf("\n" $0 ";")}}' testdatensatz5x5 | more
hostname;prozessor;RAM
a;1p;1q;1r;2p;2q;2r;3p;3q;3r;4p;4q;4r;5p;5q;5r;
b;6p;6q;6r;7p;7q;7r;8p;8q;8r;9p;9q;9r;10p;10q;10r;
c;11p;11q;11r;12p;12q;12r;13p;13q;13r;14p;14q;14r;15p;15q;15r;
d;16p;16q;16r;17p;17q;17r;18p;18q;18r;19p;19q;19r;20p;20q;20r;
e;21p;21q;21r;22p;22q;22r;23p;23q;23r;24p;24q;24r;25p;25q;25r;
tyler@wolfenstein:~/awk$
Der erste gefällt mir besser, weil kein ; am ende, auch wenn er länger ist und vermutlich länger läuft, weil zwei Schleifen bedient werden müssen.

Aber am schönsten find ich den:

Code: Alles auswählen

tyler@wolfenstein:~/awk$ awk -F';' 'BEGIN {printf("hostname;prozessor;RAM")} {if ($1==lhost) {$1=""; OFS = ";"; printf($0)} else {lhost=$1; printf("\n" $0)}}' testdatensatz5x5 | more
hostname;prozessor;RAM
a;1p;1q;1r;2p;2q;2r;3p;3q;3r;4p;4q;4r;5p;5q;5r
b;6p;6q;6r;7p;7q;7r;8p;8q;8r;9p;9q;9r;10p;10q;10r
c;11p;11q;11r;12p;12q;12r;13p;13q;13r;14p;14q;14r;15p;15q;15r
d;16p;16q;16r;17p;17q;17r;18p;18q;18r;19p;19q;19r;20p;20q;20r
e;21p;21q;21r;22p;22q;22r;23p;23q;23r;24p;24q;24r;25p;25q;25r
tyler@wolfenstein:~/awk$
Wenn man den Zeilenumbruch am Ende benötigt, dann halt noch nen END Block einfügen:

Code: Alles auswählen

awk -F';' 'BEGIN {printf("hostname;prozessor;RAM")} {if ($1==lhost) {$1=""; OFS = ";"; printf($0)} else {lhost=$1; printf("\n" $0)}} END {printf("\n")}'
@Duff: wenn du ne Erklärung brauchst kann ich die gerne liefern, habs jetzt verstanden

@Meillo: Danke für deine hervorragend gute hilfe und dein Video-Vortrag auf der CCC zu ed, sed und awk. Vor allem dein Argument, dass ed auf jedem Unix in /bin zu finden ist bringt mich dazu mir ed doch nochmal genauer anzusehen (bei lenny ist sed auch in /bin). Was MULTICS war hast du bestimmt schon gegoogelt, das hätte ich tatsächlich beantworten können ;-)

p.s.: hab ich nur das Problem, dass ständig DNS in die Hose geht, oder hat DENIC immernoch das Problem mit seinen DNS Servern von gestern nachmittag?

***EDIT***
Meillo hat geschrieben: Am Anfang wird eine leere Zeile ausgegeben. Das kann durch eine Bedingung abgestellt werden.
Da rätsel ich aber noch grade dran. Wenn ich die erste Zeile also nicht leer haben will, oder eigenen Text einsetzten will, wie setzte ich denn die Bedingung?
awk NF /etc/hosts entfernt alle leeren Zeilen, aber das bekomm ich nicht eingebaut

***EDIT2***
oh man, ist doch ganz einfach, wenn ich mal genau gelesen hätte einfach Bedingung - also nur if

Code: Alles auswählen

awk -F';' '{if (lhost=="") {lhost=$1;  printf($0); next}} {if ($1==lhost) {$1=""; OFS = ";"; printf($0)} else {lhost=$1; printf("\n" $0)}} END {printf("\n")}'
...das next war etwas kniffelig, aber war nach analyse des oputputs ohne next auch schnell klar ;-)

Jetzt bin ich aber gespannt auf deine Musterlösung, die du bestimmt schon im Kopf hattets, als du die Lösung für nur zwei Zeilen mit identischem Anfangsstring gepostet hast. Du wolltest es nur kurz und unkompliziert halten, daher hast du nicht direkt die Lösung für mehrere Zeilen mit identischem Anfangsstring gepostet.

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

Re: Zwei Zeilen mit selbem Anfangsstring zu einer zusammenfa

Beitrag von Meillo » 14.05.2010 12:20:22

Master Mayhem hat geschrieben: Jetzt bin ich aber gespannt auf deine Musterlösung, die du bestimmt schon im Kopf hattets, als du die Lösung für nur zwei Zeilen mit identischem Anfangsstring gepostet hast. Du wolltest es nur kurz und unkompliziert halten, daher hast du nicht direkt die Lösung für mehrere Zeilen mit identischem Anfangsstring gepostet.
Hier (sogar kommentiert):

Code: Alles auswählen

awk -F';' '
$1!=last {  # if hostname changes
    if (NR>1) {
        # print a newline, but not in the first line
        print "";
    }
    printf $1;  # print the hostname
    last=$1;  # save the hostname
}

{
    $1="";  # remove the hostname from the line
    printf $0;  # print the line without a newline
}

END {
    print "";  # print a newline at he very end
}
'
Use ed once in a while!

Antworten