ubuntuusers.de

awk: Wer aus letzter Zeile mit vorherigen Zeilen vergleichen

Status: Gelöst | Ubuntu-Version: Ubuntu 14.04 (Trusty Tahr)
Antworten |

jb-alvarado

Anmeldungsdatum:
28. November 2012

Beiträge: 345

Hallo Allerseits,

ich habe folgende Zeilen:

1
2
3
4
5
6
black_start:0.00 black_end:0.20
black_start:1.50 black_end:1.70
black_start:20.30 black_end:20.40
black_start:50.11 black_end:50.21
black_start:70.45 black_end:70.55
black_start:100.10 black_end:100.20

Dort möchte ich den ersten Zahlenwert der Letzten Zeilen (erste Spalte) nehmen, 30 abziehen, die vorherigen Zeilen prüfen, und wenn der Wert das letzte mal unter dem Vergleichswert (70.1) ist möchte ich diesen Angezeigt bekommen.

Also als Ergebniss müsste hier 50.11 raus kommen.

Eine Lösung habe ich schon, die wäre über drei Schritte und würde so funktionieren:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
black=$( echo "black_start:0.00 black_end:0.20
black_start:1.50 black_end:1.70
black_start:20.30 black_end:20.40
black_start:50.11 black_end:50.21
black_start:70.45 black_end:70.55
black_start:100.10 black_end:100.20" | awk -v FS="( black_start:| black_end )" '{ print $2 }' )

last=$( echo "$black" | awk 'END { print $0-30 }' )

match=$( echo "$black" | awk -v ma="$last" '{ if ( $0 < ma ) ne=$0 } END { print ne }' )

Als Einzeiler habe ich das getestet, was jedoch noch nicht ganz funktioniert:

1
2
3
4
5
6
echo "black_start:0.00 black_end:0.20
black_start:1.50 black_end:1.70
black_start:20.30 black_end:20.40
black_start:50.11 black_end:50.21
black_start:70.45 black_end:70.55
black_start:100.10 black_end:100.20" | awk -F'[: ]' '{ a[i++] = $2 } END { for (j=i-1; j>=0;) print a[j--] }'

Leider komme ich hier nicht weiter und wollte euch mal fragen ob ihr mir hier ein Tipp habt. Bei diesen Ansatz bekomme ich das als Ergebnis:

  • 20.30

  • 0.00

Schön wäre, wenn ich auch wieder -v FS="( black_start:| black_end )" verwenden könnte, und nicht nur -F'[: ]'. Das hat im realen Szenario besser geklappt.

Grüße

Jonathan

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Das würde ich alles direkt mit awk machen, denn damit kann man besser skrikpten als mit der Shell:

track@track:~$ echo 'black_start:0.00 black_end:0.20
black_start:1.50 black_end:1.70
black_start:20.30 black_end:20.40
black_start:50.11 black_end:50.21
black_start:70.45 black_end:70.55
black_start:100.10 black_end:100.20'  |  awk -F '[ :]' '{ if($2 >= 70.1) {print vorige; exit} vorige= $2}'
50.11 

Zur Erklärung: vorab stelle ich als Worttrenner ":" und " " ein, damit ich die Zahlen bequem heraustrennen kann.
Sobald der Schwellwert überschritten ist, drucke ich den vorigen Wert, den ich mir bei der vorigen Runde gemerkt habe und beende das ganze, damit er nicht noch mehr ausgibt.
Zum Verständnis der Befehle kannst Du gut in der awk- Einführung nachlesen.

Allerdings habe ich die Geschichte mit dem "30 abziehen" nicht verstanden. Das müsstest Du ggf. selber noch nachtragen.
Und ich bin davon ausgegangen, dass alle Zeilen ± gleich aussehen, dass man also einfach blind das 2. Wort nehmen kann.

LG,

track

jb-alvarado

(Themenstarter)

Anmeldungsdatum:
28. November 2012

Beiträge: 345

Hallo track, danke für die Antwort! Ich hatte oben einen falschen Code eingefügt. Mein letzter Stand war dieser:

1
2
3
4
5
6
echo "black_start:0.00 black_end:0.20
black_start:1.50 black_end:1.70
black_start:20.30 black_end:20.40
black_start:50.11 black_end:50.21
black_start:70.45 black_end:70.55
black_start:100.10 black_end:100.20" | awk -F'[: ]' '{ a[i++] = $2 } END { ne=a[i-1]-30; for ( j=i-1; j>=0; ) if ( a[j--] < ne ) print a[j--] }'

Das mit den 30 abziehen ist ein wichtiger Schritt, da ich im realen Szenario nicht weiß welchen Wert die letzte Zeile hat. Zuerst muss der Wert der letzten Zeile ermittelt werden, in diesem Beispiel ist das 100.10, von diesem muss 30 abgezogen werden, und dass Ergebnis ist dann der Vergleichswert, der mit if ($2>=$Vergleichswert) verglichen wird.

Du hast recht, meine Kenntnis über awk ist noch nicht so hoch. Aber bei so Geschichten wie Arrays durch zählen und so weiter tue ich mich generell etwas schwierig. Das macht jede Scriptsprache etwas anders und for ( j=i-1; j>=0; ) finde ich ziemlich kryptisch, gerade wenn man das nicht täglich braucht.

Edit: ich hab's fast:

1
awk -F'[: ]' '{ a[i++] = $2 } END { ne=a[i-1]-30; for ( j in a ) if ( a[j] < ne ) print a[j] }'

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Ah, ok. - In dem Fall musst Du natürlich bis zum Ende zählen.

Allerdings brauchst Du die Zeilenzahl nicht mitzzuführen, die steht fix und fertig in der Variablen NR bzw. FNR.
Außerdem bleiben die Wort-Variablen $x am Ende stehen. Damit kann man schreiben:

track@track:~$ echo "black_start:0.00 black_end:0.20
black_start:1.50 black_end:1.70
black_start:20.30 black_end:20.40
black_start:50.11 black_end:50.21
black_start:70.45 black_end:70.55
black_start:100.10 black_end:100.20" | awk -F'[: ]' '{ a[NR]= $2 } END {for(j=1;j<NR;j++) if(a[j] > $2-30) {print a[--j]; exit} }'
50.11 

Ich zähle hier ausdrücklich über den Index hoch und nicht über das Array, weil sonst die Reihenfolge nicht unbedingt erhalten bleibt.

LG,

track

jb-alvarado

(Themenstarter)

Anmeldungsdatum:
28. November 2012

Beiträge: 345

War ich ja gar nicht soweit entfernt ☺. Danke vielmals, das schaut sehr gut aus!

Antworten |