Logdatei auswerten und neue Logdatei erstellen => Nur bei bestimmtem Wert

Cardo

Cardo

Mitglied
Hi Leute,

ich bin gerade dabei ein Shell-Script zu schreiben um Logdateien auszuwerten und das Ergebnis in eine neue Datei zu schreiben.

Beispiel Logdatei:
name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = 215
name (001548) = Tux2
nachnahme (001548) = Pinguin2
anzahl (001548) = 1.215
name (001549) = Tux3
nachnahme (001548) = Pinguin3
anzahl (001549) = 5

./logauswertung logdateiname

#!/bin/bash
## Name des Scripts logauswertung

for line in $1;
do
awk '{print 2$, 3$, 4$}' $1
done

Bisher funktioniert auch alles.

Allerdings möchte ich, dass wenn die 'Anzahl' einen bestimmten Wert überschreitet, der Wert in eine neue Logdatei geschrieben wird.
Es soll quasi alles herausgefiltert werden, das unter Anzahl $2 (z.B. 500) ist.

Hat jemand ne Idee oder ein Code-Beispiel, wie ich das machen könnte?
 
Hallo,
ungetestetes Beispiel ohne awk mit read

Code:
FILE=1;
while read A NUM Z Wert;
 do 
#Klammern entfernen
F=$(echo $NUM|tr -d "()");
#wenn größer 001548 in neue Datei umleiten
if [ $F -gt 001548 ]; 
 then echo $A $F $Wert >>file_$((FILE+=1)).txt;
else
 echo $A $F $Wert >>file_${FILE}.txt;
 fi;
done< /tmp/test

Gruß Wolfgang
EDIT Bitte mach bei solchen Klammerwerten beim Posten den Haken an Grafische Smileys deaktivieren
 
Zuletzt bearbeitet:
Danke für die Schnelle Antwort.

Allerdings würd ich das ganze gern nach der Anzahl auswerten. (Den markierten)

Code:
Beispiel Logdatei:
name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = [B]215[/B]
name (001548) = Tux2
nachnahme (001548) = Pinguin2
anzahl (001548) = [B]1.215[/B]
name (001549) = Tux3
nachnahme (001548) = Pinguin3
anzahl (001549) = [B]5[/B]

Edit: Sry wegen den Smilies. Wird nicht wieder vorkommen :)

Kann man bei meinem Script-Entwurf nicht einfach sowas reinbauen?

Code:
awk '{print 2$, 3$, 4$>1000}' $1

Und noch ne Frage:
Hat es einen speziellen Grund, warum du kein AWK benutzt hast in dem Script?
 
Nun, Dein Beispiel startet für jetzt Zeile einen awk-Prozess. Wenn Deine Datei 1000 Zeilen hat, wird awk auch 1000x gestartet. Wolfgang macht alles direkt in der Shell - das dürfte auch locker um den Faktor 50-100 schneller sein :-)

Wenn Du nur die Zeilen mit "anzahl" nehmen möchtest, kannst Du vorher ja noch ein if [ $A = "anzahl" ]; then einbauen, und hinterher ein "fi".

Heiko
 
Cardo schrieb:
Danke für die Schnelle Antwort.

Allerdings würd ich das ganze gern nach der Anzahl auswerten. (Den markierten)

Code:
Beispiel Logdatei:
name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = [B]215[/B]
name (001548) = Tux2
nachnahme (001548) = Pinguin2
anzahl (001548) = [B]1.215[/B]
name (001549) = Tux3
nachnahme (001548) = Pinguin3
anzahl (001549) = [B]5[/B]

Edit: Sry wegen den Smilies. Wird nicht wieder vorkommen :)

Kann man bei meinem Script-Entwurf nicht einfach sowas reinbauen?

Code:
awk '{print [color=red]2$, 3$, 4$[/color]>1000}' $1
Das rot markierte wird nicht gehen. Erst $, dann die Feldnummer ;)

Wenn du schon awk haben willst, dann ist die for in Geschichte nicht nötig.
Bin zwar kein Freund von awk, (da nehm ich immer Perl ;) ) aber folgendes sollte vom Prinzip her gehen.
Code:
awk 'BEGIN{Datei1="Name1";Datei2="Name2"}{if ( $4 <= 20 ){print $2 $3 $4 >Datei1}else {print $2 $3 $4 >Datei2}}' testfile
Musst nur die Namen und den Wert (hier 20 ) anpassen
Und noch ne Frage:
Hat es einen speziellen Grund, warum du kein AWK benutzt hast in dem Script?
Dazu wurde schon etwas gesagt.
Deine for i in Schleife ist absolut unnütz, da awk ja ohnehin die Datei liest.
Wenn in $1 der Dateiname steht, kannst du den auch an awk verfüttern.
awk '<CODE>' $1

Das mit den Smilies war nicht bös gemeint, sondern nur ein Hinweis damit der Code nicht zerstört wird. Manche wissen nicht wie das abzustellen ist.
Erleichtert allen die Lesbarkeit. ;)

Gruß Wolfgang
 
Stimmt, ist klar, dass die Version schneller gehen würde.

Öhm nun... Also das mit der Anzahl hab ich doch anders gemeint.

name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = 215

Das Soll nicht nach der in den Klammern stehenden Zahl ausgewertet werden, sondern nach der markierten Zahl.

Geht sowas auch mit dem Skript von Wolfang oder wäre dafür awk (evtl. zusammen mit sed) besser geeignet?
 
Cardo schrieb:
for line in $1;
do
awk '{print 2$, 3$, 4$}' $1
done

Wenn Du
Code:
cat $1 | awk '{print$2, $3, $4}'
benutzt wird nicht jedes Mal ein awk Thread gestartet sondern awk behandelt die Datei von vorne bis hinten. Und dann kannst Du da nach Belieben diverse awk Logik unterbringen.
z.B.
Code:
cat $1 | awk '{if ( $2 > 4711) { next} print$2, $3, $4}'
 
framp schrieb:
Wenn Du
Code:
cat $1 | awk '{print$2, $3, $4}'
benutzt wird nicht jedes Mal ein awk Thread gestartet sondern awk behandelt die Datei von vorne bis hinten. Und dann kannst Du da nach Belieben diverse awk Logik unterbringen.
z.B.
Code:
cat $1 | awk '{if ( $2 > 4711) { next} print$2, $3, $4}'
Wozu hier cat?
Das ist exat das Gleiche, und spart einen Prozess, löst aber nicht das Problem von Cardo.
awk '{if ( $2 > 4711) { next} print$2, $3, $4}' $1
useless use of cat ;)
Cardo schrieb:
Das Soll nicht nach der in den Klammern stehenden Zahl ausgewertet werden, sondern nach der markierten Zahl.

Genau das macht mein Vorschlag.
Hast du den mal getestet?
Natürlich gehe ich davon aus, dass nur in Zeilen mit "anzahl" eine Zahl in $4 folgt.
Aber auch das lässt sich komplettieren:
Code:
awk 'BEGIN{Datei1="Name1";Datei2="Name2"}{if ( /anzahl/ && $4 <= 20 ){print $2 $3 $4 >Datei1}else {print $2 $3 $4 >Datei2}}' test
Hier teste ich, ob "anzahl" vorkommt und das vierte Feld - also die Zahl hinter dem = - größer 20 iist.
awk ist hier geeignet, da die Shell von sich aus nur mit integer rechnet, und so ein weiterer Prozess wie etwa bc notwendig würde.
awk kann aber selbst mit float umgehen.

Gruß Wolfgang
 
Also ich hab Wolfgangs Script mal getestet

Code:
awk 'BEGIN{Datei1="Name1";Datei2="Name2"}{if ( /anzahl/ && $4 <= 20 ){print $2 $3 $4 >Datei1}else {print $2 $3 $4 >Datei2}}' test

Das ganze Funktioniert an sich ganz gut, aber es gibt da noch ein paar kleine Probleme:

Also die Datei1 brauch ich gar nicht. Ich hab jetzt einfach mal am ende vom Skript ein "rm Name1" eingebaut. Kann man Problem das "schöner" lösen?

Nächstes Problem:
In der Datei2 stehen dann auch die Strings also die Buchstaben drin. Die Filtert das Script bei dem >Zahl leider nicht heraus.

Code:
Beispiel Logdatei:
name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = 215
name (001548) = Tux2
nachnahme (001548) = Pinguin2
name (001549) = Tux3
nachnahme (001548) = Pinguin3

Da aller guten in drei sind gibts auch noch ein drittes Problem:
Die Werte, die bei Anzahl über 999 stehen, werden dann alle mit einem Punkt getrennt. Zum Beispiel 1.434. Muss man den Punkt vorher rausfiltern oder kann man einfach noch eine Bedingung einbauen?
______________________________________________________________
Und danke an alle, die hier so toll helfen. Das hier scheint ein Super Forum zu sein. Mit hohem Niveau :))
 
Cardo schrieb:
Also ich hab Wolfgangs Script mal getestet

Code:
awk 'BEGIN{Datei1="Name1";Datei2="Name2"}{if ( /anzahl/ && $4 <= 20 ){print $2 $3 $4 >Datei1}else {print $2 $3 $4 >Datei2}}' test

Das ganze Funktioniert an sich ganz gut, aber es gibt da noch ein paar kleine Probleme:

Also die Datei1 brauch ich gar nicht. Ich hab jetzt einfach mal am ende vom Skript ein "rm Name1" eingebaut. Kann man Problem das "schöner" lösen?
Dann leg sie einfach nicht an. ;)
Wenn du nur bestimmte Daten in einer Datei haben willst, dann kannst du die direkt ausfiltern und ausserhalb des Scriptes umleiten:
awk '{<FILTERSCRIPT>}' Input >Output

Nächstes Problem:
In der Datei2 stehen dann auch die Strings also die Buchstaben drin. Die Filtert das Script bei dem >Zahl leider nicht heraus.

Code:
Beispiel Logdatei:
name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = 215
name (001548) = Tux2
nachnahme (001548) = Pinguin2
name (001549) = Tux3
nachnahme (001548) = Pinguin3
Dann erklär dein Problem bitte genauer.
Welche Daten willst du nach welchem Kriterium in welcher Datei speichern?
Schreib einfach mal wie das Ergebnis bei deinem Beispiel aussehen soll.
Du hast es selbst in der Hand welches Feld du ausgeben willst.
Einen Blick in die Manpage von awk wird dir nicht erspart bleiben. ;)


Da aller guten in drei sind gibts auch noch ein drittes Problem:
Die Werte, die bei Anzahl über 999 stehen, werden dann alle mit einem Punkt getrennt. Zum Beispiel 1.434. Muss man den Punkt vorher rausfiltern oder kann man einfach noch eine Bedingung einbauen?
______________________________________________________________
Und danke an alle, die hier so toll helfen. Das hier scheint ein Super Forum zu sein. Mit hohem Niveau :))

Ich bin davon ausgegangen, dass die Werte mit dem Punkt Gleitkommazahlen sind.
Wenn dem nicht so ist, musst du diesen vor der Auswertung natürlich entfernen.
Code:
$ echo "anzahl (00014789) = 1.200"|awk '{ if (/anzahl/){gsub ("\.","",$4)} if ($4 gt 999 ){print $4}}'
1200

gsub entfernt hier den Punkt aus dem vierten Feld, wenn die Zeile "anfang" enthält. Danach kannst du damit alle numerischen Vergleiche durchführen.

Fazit:
Formuliere nochmal genau an Hand der Daten was dene Aufgabe ist.
Wie die Daten aussehen, wissen wir, aber wie das Ergebnis genau aussehen soll nicht.

Gruß Wolfgang
 
Hier mal die Beispiel logfile und wie die neue Datei nach der bearbeitung aussehen soll:

Code:
#Logdatei original

name (001547) = Tux
nachnahme (001547) = Pinguin
anzahl (001547) = 215
name (001548) = Tux2
nachnahme (001548) = Pinguin2
anzahl (001548) = 1.215
name (001549) = Tux3
nachnahme (001548) = Pinguin3
anzahl (001549) = 5

Code:
Gewünschtes Ergebnis nach Scriptdurchlauf:
#Wenn bei Anzahl >200 eingestellt wäre.
anzahl (001547) = 215
anzahl (001548) = 1.215
 
Hallo

Na dann ist doch schon fast alles da was du suchst da. ;)
Code:
$ awk '/anzahl/{gsub ("\.","",$4); if(($4+0)>200){print}}' test
anzahl (001547) = 215
anzahl (001548) = 1215
  • Bearbeite nur Zeilen die anzahl enthalten -> /anzahl/
  • Entferne im vierten Feld den Punkt -> gsub("\.","",$4)
  • Addiere zu $4 0 hinzu und vergleiche das Ergebnis mit 200 , wenn wahr printe Zeile aus.

Der Trick $4+0 zwingt awk zum numerischen Vergleich.
Da wir auf dieser Variablen schon mit gsub gearbeitet haben, wird $4 als String vorgemerkt. Eine Addition mit 0 erzwingt diesen Wert wieder numerisch.
Siehe manpage von awk. :rtfm:

Wenn du die Ausgabe in eine Datei umleiten willst einfach :
Code:
$ awk '/anzahl/{gsub ("\.","",$4); if(($4+0)>200){print}}' test >Ausgabedatei

Gruß Wolfgang
 
Wow, jetzt hab ich fast das gewünschte Ergebnis.

Allerdings bekomm ich bei dem code

Code:
awk '/anzahl/{gsub ("\.","",$4); if(($4+0)>200){print}}' testlog >Ausgabedatei

folgende Fehlermeldung:

awk: cmd. line:1: warning: escape sequence `\.' treated as plain `.'
Die Ausgabedatei wird dann zwar geschrieben, es steht aber nichts drin.

Also hab ich obem beim gesub einfach ein Leerzeichen gemacht ("\ .","",$4).
Es kommt zwar immer noch die Fehlermeldung (aber ohne Punkt), jedoch wird das richtige Ergebis in die Datei geschrieben.

Woran könnte das liegen?
 
Hallo

Welche Shell benutzt du denn?
Welches OS?

Bei mir unter bash geht folgendes:
$ awk '/anzahl/{gsub ("\.","",$4); if(($4+0)>200){print}}' test
anzahl (001547) = 215
anzahl (001548) = 1215
Der Punkt muss geschützt werden, da er ein Metazeichen für awk darstellt.
Was du genacht hast, ist ein leerzeichen zu escapen, was natürlich nicht sinnvoll ist.
Wenn bei dir das Ergebnis auch ohne \. stimmt, dann kannst du auch folgendes nutzen:
$ awk '/anzahl/{gsub (".","",$4); if(($4+0)>200){print}}' test
Portabler könnte aber das hier sein:
$ awk '/anzahl/{gsub ("[.]","",$4); if(($4+0)>200){print}}' test
anzahl (001547) = 215
anzahl (001548) = 1215

Gruß Wolfgang
 
Zuletzt bearbeitet:
Morgen Wolfgang,

also ich nutze United Linux und die Bash.


Die Version funktioniert Super:
Code:
$ awk '/anzahl/{gsub ("[.]","",$4); if(($4+0)>200){print}}' test

EDIT:
Ich hab einfach zwei ' bei $anzahl gesetzt. Geht jetzt ^^

Also, jetzt möchte ich nur noch was einbauen, wenn keine Anzahl gesetzt wurde...
Ich habs mal wie folgt probiert:

Code:
#!/bin/bash
anzahl=$2
if test $2 -eq ' '
then
anzahl='200'
awk '/anzahl/{gsub ("[.]","",$4); if(($4+0)>'$anzahl'){print}}' $1 > auswertung

Das Funktioniert bei mir leider nicht.
Hat jemand ne Idee, wie ich das Problem lösen könnte?
Also es soll überprüft werden, ob nichts als $2 angeben wurde. Wenn das der Fall ist, soll die Variable anzahl auf 200 gesetzt werden.

EDIT:

Ich hab das ganze jetzt einfach so gelöst:

Code:
#!/bin/bash
anzahl=$2
if test $2 -eq 0
then
anzahl='200'
awk '/anzahl/{gsub ("[.]","",$4); if(($4+0)>'$anzahl'){print}}' $1 > auswertung

Also wenn man als Wert
./script.sh Dateiname 0
eingibt, wird 200 als Standart wert genommen.

Jetzt aber noch mal ein großes Special THX an Wolfgang und alle anderen die geholfen haben!
 
Zuletzt bearbeitet:

Ähnliche Themen

Shell Skript beschleunigen

Prblem mit zeilenweises auslesen von Datei und schreiben nach mysql

Werte in 2 Variablen subtrahieren

Shell if-Abfrage mit equal or greater wirft Fehlermeldung unary operator expected

MySQL-Abfrage an Variable übergeben

Zurück
Oben