(e|f|)grep vs. pregmatch
Thoralf Knuth
- webserver
Hallo,
ich bin immer noch[1] dabei, meine Logs, die komplett alle meine (Sub-)Domains enthalten, zu splitten. Mit PHP ist das mittlerweile kein Problem. Mit Hilfe von O'Reillys PHP Cookbook habe ich eine(n?) PCRE, mit dem ich die Domain rausnehme, ob mit oder 'www.':
/* Client IdentD User [Zeit] "method Request protocol" Status Bytes vhost "Referer" "UserAgent" "Proxy-Real-IP" */
$sPattern = '/^([^ ]+) ([^ ]+) ([^ ]+) ([[^]]+]) "(.*) (.*) (.*)" ([0-9-]+) ([0-9-]+) (www.|)(.*) "(.*)" "(.*)" "(.*)"$/';
Mit einem einfachen preg_match() und list() splitte ich mir den Eintrag auf und kann dann je nach vhost weiter verfahren.
Nun will ich das natürlich direkt mit grep oder egrep machen. Nur das kriegt er nicht hin.
Ich hab mit ein Test-Log mit Auszügen genommen und das mit PHP "auswerten" lassen und habe das erwartete und erwünschte Ergebnis.
grep '^([^ ]+) ([^ ]+) ([^ ]+) ([[^]]+]) "(.*) (.*) (.*)" ([0-9-]+) ([0-9-]+) (www.|)(example.org) "(.*)" "(.*)" "(.*)"$' dateiname
gibt mir keine einzige Zeile als Ergebnis. ('/' an Anfang und Ende entfernz, mit und ohne '-e' probiert)
grep 'example.org' dateiname
gibt mir wiederrum alle die Zeilen, die example.org im Eintrag haben. Ist zwar richtig, aber nutzt mir nichts, da dann ja auch Referer ausgewertet werden.
Fernziel, aber soweit bin ich noch nicht, ist eine backreference im Dateinamen, so dass ich alle Zeilen ausgeben lassen kann in eine Datei, die den vhost im Dateinamen trägt. Aber das ist noch gar nicht das Ziel. Ich wäre schon dankbar, wenn grep meinen RegExp fressen würde.
Hat mir jemand Tipps, Hinweise, Watschn?
Gruß & Dank, Thoralf
[1] http://forum.de.selfhtml.org/archiv/2004/2/73573/
hi!
grep '^([^ ]+) ([^ ]+) ([^ ]+) ([[^]]+]) "(.*) (.*) (.*)" ([0-9-]+) ([0-9-]+) (www.|)(example.org) "(.*)" "(.*)" "(.*)"$' dateiname
Also du musst auf jeden Fall egrep aufrufen, da das ein erweiterter
regulärer Ausdruck ist. Und offensichtlich bist du etwas über die
Zeichenklassen gestolpert:
Most metacharacters lose their special meaning inside lists. To
include a literal ] place it first in the list. Similarly, to
include a literal ^ place it anywhere but first. Finally, to
include a literal - place it last.
Ergibt dann:
egrep '[1]+ [^ ]+ [^ ]+ [[^]]+] ".*" [0-9-]+ [0-9-]+ subdomain.test.de ".*" ".*" ".*"' access-log
Fernziel, aber soweit bin ich noch nicht, ist eine backreference
im Dateinamen, so dass ich alle Zeilen ausgeben lassen kann in
eine Datei, die den vhost im Dateinamen trägt.
Hm, ich glaube nicht, dass das so einfach möglich ist mit einem
einfachen Kommandozeilenaufruf. Du kannst ja keine Backreferences
aus dem grep nach draußen weitergeben, um dadurch irgendwelche
Dateinamen zu beeinflussen (das wäre ja nicht mal ein grep-Parameter,
sondern das Ziel einer >-Umleitung). Und mit älteren grep-Versionen
(<2.5) kann man auch keine Teilstrings aus einer Zeile ausschneiden.
Die einfachste Lösung wäre IMHO, ein kleiner Skript zu schreiben, das
diese Aufgabe erledigt. In Perl zb. wäre das etwa ein Zehnzeiler.
bye, Frank!
^ ↩︎
Hallo Frank,
erstmal besten Dank für die Antwort.
Also du musst auf jeden Fall egrep aufrufen, da das ein erweiterter
regulärer Ausdruck ist.
Yep, das hab ich mir schon gedacht, aber wenn's nicht klappt, dann fängt man halt an zu probieren. ;)
Und offensichtlich bist du etwas über die Zeichenklassen gestolpert:
Versteh im Moment nicht, was Du meinst, bin aber in Sachen Regular Expressions grade erst dem Anfängerstadium etwas entwachsen. Ich seh, dass Du die Gruppierungen rausgenommen hast, die ich eben für die Backreferences noch drin hatte, im Nachhinein ist das logisch, dass das für bloßes Suchen nicht funktionieren kann.
Most metacharacters lose their special meaning inside lists. To
include a literal ] place it first in the list. Similarly, to
include a literal ^ place it anywhere but first. Finally, to
include a literal - place it last.
Was meinst Du damit, ist ein Auszug aus man grep, soweit ich das sehe. Aber ich versteh im Moment den Zusammenhang nicht. Wenn Du die Muße hast, könntest das mal einen Tick ausführlicher (juristentauglicher ;)) erklären. Ich lerne durch dieses Suchen und Nachvollziehen nämlich eine Menge. Danke!
egrep '[1]+ [^ ]+ [^ ]+ [[^]]+] ".*" [0-9-]+ [0-9-]+ subdomain.test.de ".*" ".*" ".*"' access-log
holpert dann immer noch am optionalen www vor dem vhost, aber wenn das Backreferencing nicht geht, womit ich gerechnet habe, dann nutzt das bloße grepen letzlich eh nichts mehr, dann werd ich das doch mit Script machen, das klappt nämlich. :)
Du kannst ja keine Backreferences aus dem grep nach draußen weitergeben,
um dadurch irgendwelche Dateinamen zu beeinflussen (das wäre ja nicht
mal ein grep-Parameter, sondern das Ziel einer >-Umleitung).
Das hab ich fast erwartet, deswegen Fernziel. Soweit ich das überblickt hatte, war mir klar, dass es nicht geht. Ich war nur eben nicht sicher, ob ich es wirklich komplett überblicke, oder ob ich einfach nicht weit genug schauen kann. ;)
Die einfachste Lösung wäre IMHO, ein kleiner Skript zu schreiben, das
diese Aufgabe erledigt. In Perl zb. wäre das etwa ein Zehnzeiler.
Für Perl bin ich zu doof, PHP läuft das aber schon. :)
Danke!
Thoralf
^ ↩︎