awk 2 Zeilen vergleichen

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
nippler92
Beiträge: 4
Registriert: 26.08.2013 09:00:49

awk 2 Zeilen vergleichen

Beitrag von nippler92 » 26.08.2013 09:06:22

Hallo zusammen,

ich hab ein kleines Problem und komme nicht weiter, evtl könnt ihr mir ja helfen :)

ich habe einen 10 Zeilen Langen text und möchte wenn das erste Feld des ersten records mit einem bestimmten string übereinstimmt dann das erste feld mit des 5. records mit einem anderen string vergleichen sozuisagen sowas...

Code: Alles auswählen

NR==1 $1 ~ /sting_1/ {
                 NR==5 $1 ~ /sting_2/ {counter++;}
                               ;}
Das dass so nicht geht weiß ich aber ich denke das veranschaulicht mein Problem ganz gut :)

LG nippler92
Zuletzt geändert von Meillo am 26.08.2013 11:53:33, insgesamt 1-mal geändert.
Grund: code-Tags ergaenzt

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

Re: awk 2 Zeilen vergleichen

Beitrag von Cae » 26.08.2013 11:53:59

Also Input waere z.B.

Code: Alles auswählen

   1       2       3       4       5       6
1  foobar  foo     bar     baz     foo     bar
2  foo     bar     baz     foo     bar     foobar
3  bar     baz     foo     bar     foobar  foo
4  baz     foo     bar     foobar  foo     bar
5  foo     bar     foobar  foo     bar     baz
6  bar     foobar  foo     bar     baz     foo
Wenn 1|1 jetzt foobar ist und 5|1 foo, soll irgendetwas passieren?

Code: Alles auswählen

$ awk '1==FNR&&"foobar"==$1{f=1}5==FNR&&"foo"==$1&&f{print"found"}' <data
Ich setze ein Flag, was bei 5==FNR ausgelesen wird (uninitalisierte Variablen sind grundsaetzlich ==0). FNR hat uebrigens den Vorteil, dass man mehrere Dateien uebergeben kann, die jeweils einen eingenen NR-Zaehler haben, anstatt dem globalen NR-Zaehler.

Nochmal in leserlich geschrieben:

Code: Alles auswählen

$ awk '
	1 == FNR && "foobar" == $1 {
		f = 1;
	}
	5 == FNR && "foo" == $1 && f {
		print("found");
	}
' <data
Willkommen im Forum!

Gruss 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
Meillo
Moderator
Beiträge: 9238
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: awk 2 Zeilen vergleichen

Beitrag von Meillo » 26.08.2013 11:57:05

nippler92 hat geschrieben: ich habe einen 10 Zeilen Langen text und möchte wenn das erste Feld des ersten records mit einem bestimmten string übereinstimmt [...]
Das kannst du so haben:

Code: Alles auswählen

NR==1 && $1 == "foo" { ... }
Du brauchst die Verundung (&&) und wenn du exakt vergleichen willst, dann ist ein Stringvergleich angebrachter als Pattern matching.

dann das erste feld mit des 5. records mit einem anderen string vergleichen sozuisagen sowas...
Das habe ich nicht kappiert. Kannst du bitte nochmal genau erklaeren was dann passieren soll. Mach bitte auch ein Beispiel wie es davor und danach aussehen soll.
Use ed once in a while!

nippler92
Beiträge: 4
Registriert: 26.08.2013 09:00:49

Re: awk 2 Zeilen vergleichen

Beitrag von nippler92 » 27.08.2013 07:57:17

Danke für die schnellen Antworten :)
dann das erste feld mit des 5. records mit einem anderen string vergleichen sozuisagen sowas...
Bisschen schlecht geschrieben, ich machs einfach mal wieder gesagt hast am konkreten Beispiel

Output>>>

JobState=RUNNING Reason=None Dependency=(null)
-
-
-
-
Partition=gpu AllocNode:Sid=tauruslogin2:26371
-
-
-
NumNodes=1 NumGPUs=1 GPUs/Task=1 ReqS:C:T=*:*:*


Also wenn JobState=RUNNING soll dieser Job beachtet werden ( erstes if )
wenn dem so ist kann ich vergleichen ob ich auf einer gpu bzw cpu Partition bin ( zweites if )
zum schluss wird dann noch errechnet auf wiele gpus/cpus der job zugreift und fertig :)

Als Rezension auf die schon geschriebenen Beiträge mal ein Verständnisversuch

FNR inkrementiert wie NR durch die Records, wenn ich Ihn aber auf 0 setzte beginnt er in einem neuen File? - hab ich ncoh nicht zu 100% verstanden
FNR
FNR is the current record number in the current file. FNR is incremented each time a new record is read (see section Explicit Input with getline). It is reinitialized to zero each time a new input file is started.
NF
Cae hat geschrieben: Nochmal in leserlich geschrieben:

Code: Alles auswählen

$ awk '
	1 == FNR && "foobar" == $1 {
		f = 1;
	}
	5 == FNR && "foo" == $1 && f {
		print("found");
	}
' <data
Ich denke es müsste so aussehen

Code: Alles auswählen

 "foobar" == $1 $$ ( 5 == FNR && "foo" == $1 && f ){
		f = 1;
	}
oder halt mit zwei if anweisungen.


Danke schonmal für die Hilfe und das willkommen :)

LG nip

uname
Beiträge: 12403
Registriert: 03.06.2008 09:33:02

Re: awk 2 Zeilen vergleichen

Beitrag von uname » 27.08.2013 08:41:34

Also ich kann weder awk gut programmieren noch habe ich dein Problem wirklich verstanden. Insgesamt sehe ich es aber so, dass die Zeilennummer (z.B. + 5 Zeilen) eigentlich gar keine Bedeutung hat. Du möchtest eher wenn ein Matching auf z.B. "JobState=RUNNING" vorkommt die Zeilen mit "Partition" und NunNodes nutzen. Hierzu braucht dein Programm mindestens drei Zustände. Die Variable f mit den Werten 0 und 1 wird nicht ausreichen. Statt "f" habe ich mal "status" gewählt, um es zu verdeutlichen.

Beispiel:

Code: Alles auswählen

awk '{if ($0 ~ /^JobState/) { status=1}; if ((status==1) && ($0 ~ /^Partition/)) {status=2}; if ((status==2) && ($0 ~ /^NumNodes/)) {status=0;print $0}  }' test.txt
Wirklich schön ist es nicht. Die Suchbegriffe musst du evtl. noch anpassen. Ich habe mal per regulären Ausdrücken nach den oben genannten Begriffen am Anfang der Zeile gesucht. Die Werte selbst musst du aus den Zeilen noch irgendwie rausgenerieren (bei status=1, status=2) und verarbeiten (bei status=0). Die Ausgabe von "print $0" kannst du natürlich weglassen. Vielleicht hilft es ein wenig.

Vielleicht kann mal jemand prüfen ob die doppelten Klammerungen in den if-Anweisungen notwendig sind.

nippler92
Beiträge: 4
Registriert: 26.08.2013 09:00:49

Re: awk 2 Zeilen vergleichen

Beitrag von nippler92 » 27.08.2013 09:32:02

Könnte so klappen, wenn awk nicht zeilenweise arbeiten würde.
awk führt das geschriebene Skript für jede Zeile neu aus. Ich habs jetzt über getline gelöst, bzw bin ich gerade daran es zu lösen :)

uname
Beiträge: 12403
Registriert: 03.06.2008 09:33:02

Re: awk 2 Zeilen vergleichen

Beitrag von uname » 27.08.2013 09:34:53

awk führt das geschriebene Skript für jede Zeile neu aus.
Jein. Die äußere geschweifte Klammer wird entsprechend oft durchlaufen. awk wird nur einmal für die Datei ausgeführt.

awk arbeitet zwar zeilenweise aber genau dafür ist ja die Variable "status" dar, um nicht zu vergessen wo in der Logdatei man sich gerade befindet ;-) Du könntest sogar das ganze Zeug in Arrays packen und dann innerhalb des awk-Scriptes (z.B. END-Sequenz) auf beliebige Zeilen wieder zugreifen.

Generell würde ich sowas im übrigen eher in Perl oder einer anderen Scriptsprache schreiben. Mag aber daran liegen, dass ich awk auch nicht wirklich programmieren kann.

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

Re: awk 2 Zeilen vergleichen

Beitrag von Meillo » 27.08.2013 11:44:59

uname hat geschrieben:

Code: Alles auswählen

awk '{if ($0 ~ /^JobState/) { status=1}; if ((status==1) && ($0 ~ /^Partition/)) {status=2}; if ((status==2) && ($0 ~ /^NumNodes/)) {status=0;print $0}  }' test.txt
Es mag ja cool sein in awk Einzeiler zu schreiben aber nur dann wenn man sie danach nicht mehr lesen muss. Darum nochmal lesbar:

Code: Alles auswählen

awk '
{
    if ($0 ~ /^JobState/) {
        status=1
    }
    if ((status==1) && ($0 ~ /^Partition/)) {
        status=2
    }
    if ((status==2) && ($0 ~ /^NumNodes/)) {
        status=0
        print $0
    }
}
' test.txt
Wenn nun die einzelnen ifs fuer jede Zeile ausgefuehrt werden sollen, dann kann man sich den aeusseren Block sparen und das implizite ``$0 ~'' nutzen:

Code: Alles auswählen

awk '
$0 ~ /^JobState/ {
        status=1
}
(status==1) && /^Partition/ {
        status=2
}
(status==2) && /^NumNodes/ {
        status=0
        print
}
' test.txt

Nun aber nochmal zum konkreten Problem. Ich bin zu diesem Script gekommen:

Code: Alles auswählen

awk '
NR==1 {
        if (!/^JobState=RUNNING/) {
             exit
        }
        line1=$0
}
NR==5 {
        line5=$0
}
NR==9 {
        print line1
        print line5
        print $0
        exit
}
' test.txt
Also wenn JobState=RUNNING soll dieser Job beachtet werden ( erstes if )
Ist beruecksichtigt.
wenn dem so ist kann ich vergleichen ob ich auf einer gpu bzw cpu Partition bin ( zweites if )
Soll das Script unterschiedlich reagieren ob es `gpu' oder `cpu' ist? Wenn ja, wie?
zum schluss wird dann noch errechnet auf wiele gpus/cpus der job zugreift und fertig :)
Wer errechnet? Das Script? Wenn ja, wie? Und ist dein Beispiel nun die Eingabe oder die Ausgabe des Scriptes. Bitte liefere doch sowohl das eine als auch das andere und am besten fuer den `cpu'- als auch den `gpu'-Fall. Wir sind noch immer viel zu sehr am Raten was du willst.
Use ed once in a while!

nippler92
Beiträge: 4
Registriert: 26.08.2013 09:00:49

Re: awk 2 Zeilen vergleichen

Beitrag von nippler92 » 27.08.2013 12:34:03

Pearl werd ich mir später nochmal anschaun, muss jetzt erstmal damit klar kommen, man kann ja nicht immer aufhören was zu lernen wenn man mal nicht weiter kommt :P

Ich habs so umgesetzt (läuft zwar immer noch nicht aber das bekomm ich auch ncoh hin).

Code: Alles auswählen

                             $1 ~ /JobState=RUNNING/
                                                        {       
                                                                run++;
                                                            #im output gibt es nur 12 Zeilen die durchlaufen werden müssen 
                                                            while(i < 12)                                           
                                                                {                                       
                                                                        getline;
                                                                        {if ($1 == "Partition=gpu")
                                                                                {               
                                                                                        while($1 != NumNodes)
                                                                                        {
                                                                                                getline;
                                                                                                {if ($1 == "NumNodes")
                                                                                                        {               
                                                                                                                print("test");
                                                                                                                numnodes=gensub(/NumNodes=/,"","g",$1); 
                                                                                                                numnodes=gensub(/-[0-9]*/,"","g",numnodes);     
                                                                                                                getline;
                                                                                                                getline;
                                                                                                                {if ($2 == "Gres=gpu:2")
                                                                                                                        working_gpus+=(numnodes*2);
                                                                                                                }
                                                                                                                {if ($2 == "Gres=gpu:1")
                                                                                                                        working_gpus+=(numnodes*1);
                                                                                                                }
                                                                                                        }
                                                                                                }
                                                                                        }                                                                                       
                                                                                }
                                                                        }
                                                                        i++
                                                                }       
                                                        }
Meillo, ja das script soll unterschiedlich reagieren wenn gpus bzw cpus verwendet werden, im grunde genommen schau ich wenn gpus genutzt werden ob wieviele genutzt werden und gebe das dann später in meiner Ausgabe aus, für die cpus gibts nen schönes kommando auf dem Server, für die gpus leider nicht :(
Was hälst du von dem obigen Ausschnitt?

Antworten