hier haben sich ja schon wiederholt einige als wahre Meister der regulären
Ausdrücke und deren Nutzung in grep, sed, etc. gezeigt. Ich hätte da eine
Aufgabe, für deren Lösung mir nur eine sehr monströse Pipeline eingefallen
ist:
Gegeben ist eine per grep und cut aus einem Logfile extrahierte Liste von
IP-Adressen, eine Adresse pro Zeile in der üblichen durch Punkte getrennten
Dezimaldarstellung. Die Zahlen treten natürlich ein-, zwei- und dreistellig
bunt gemischt auf. Ich möchte nun eine nach allen vier Oktetten sortierte
Liste dieser Adressen, d. h. das 1. Oktett ist der Primärschlüssel, das 2.
der Sekundärschlüssel usw.
Die ersten Versuche brachten nicht das gewünschte Ergebnis (jedenfalls nicht
auf meinem System):
grep 'DROP-TCP.*DPT=135' /var/log/messages | cut -d ":" -f4 | \
cut -d " " -f5 | cut -c 5- | sort -n -t "." -k 1,4 | uniq
grep 'DROP-TCP.*DPT=135' /var/log/messages | cut -d ":" -f4 | \
cut -d " " -f5 | cut -c 5- | sort -g -t "." -k 1,4 | uniq
Danach habe ich mal mit sed gespielt und bin letztlich auf folgende ziemlich
monströse Lösung gekommen:
grep 'DROP-TCP.*DPT=135' /var/log/messages | cut -d ":" -f4 | \
cut -d " " -f5 | cut -c 5- | sed -e 's/\./\.\./g' | \
sed -e 's/.*/\.&\./g' | sed -e 's/\.\([0-9]\)\./\.0\1\./g' | \
sed -e 's/\.\([0-9][0-9]\)\./\.0\1\./g' | sed -e 's/\.\./\./g' | \
sort | uniq | sed -e 's/\.0\{1,2\}\([0-9]\{1,2\}\)/\.\1/g' | \
sed -e 's/^\.\(.*\)\.$/\1/g'
Dies macht zwar das was ich erreichen will, aber ich denke das es auch noch
andere (kürzere) Lösungen gibt. Vorschläge?
Günter
> grep 'DROP-TCP.*DPT=135' /var/log/messages | cut -d ":" -f4 | \
> cut -d " " -f5 | cut -c 5- | sed -e 's/\./\.\./g' | \
> sed -e 's/.*/\.&\./g' | sed -e 's/\.\([0-9]\)\./\.0\1\./g' | \
> sed -e 's/\.\([0-9][0-9]\)\./\.0\1\./g' | sed -e 's/\.\./\./g' | \
> sort | uniq | sed -e 's/\.0\{1,2\}\([0-9]\{1,2\}\)/\.\1/g' | \
> sed -e 's/^\.\(.*\)\.$/\1/g'
Du kannst alle nacheinander ausgeführten sed-Aufrufe in eine Datei
schreiben und dann mit "sed -f" aufrufen. Das sieht dann schon deutlich
entspannter aus.
> Dies macht zwar das was ich erreichen will, aber ich denke das es auch
> noch andere (kürzere) Lösungen gibt. Vorschläge?
Schickst Du einmal eine Muster-Zeile und wie sie nach der Umformung
aussehen soll?
Dirk
--
Blog: http://www.deimeke.net/dirk/blog/
> Du kannst alle nacheinander ausgeführten sed-Aufrufe in eine Datei
> schreiben und dann mit "sed -f" aufrufen. Das sieht dann schon deutlich
> entspannter aus.
sicher, aber das ist ja eigentlich keine Vereinfachung meiner Operation.
>> Dies macht zwar das was ich erreichen will, aber ich denke das es auch
>> noch andere (kürzere) Lösungen gibt. Vorschläge?
>
> Schickst Du einmal eine Muster-Zeile und wie sie nach der Umformung
> aussehen soll?
nach dem grep und cut erhalte ich eine Liste in der folgenden Bauart:
217.91.37.7
87.78.52.97
87.78.55.70
201.9.24.235
213.5.31.195
84.44.214.75
87.78.46.132
195.14.205.35
195.14.207.70
201.19.143.97
213.196.195.9
213.196.252.3
213.28.164.61
81.173.163.16
81.173.172.69
195.14.218.198
195.14.223.213
201.42.181.117
213.140.241.33
213.168.108.73
213.168.111.14
Daraus möchte ich eine sortierte Liste in dieser Bauart generieren: grobe
numerische Sortierung nach dem 1. Oktett, was dort gleich ist wird
numerisch nach dem zweiten Oktett weiter sortiert usw.
81.173.163.16
81.173.172.69
84.44.214.75
87.78.46.132
87.78.55.70
87.78.52.97
195.14.205.35
195.14.207.70
195.14.218.198
195.14.223.213
201.9.24.235
201.19.143.97
201.42.181.117
213.5.31.195
213.28.164.61
213.140.241.33
213.168.108.73
213.168.111.14
213.196.195.9
213.196.252.3
217.91.37.7
Meine Lösung ergänzt erst einige Punkte, dann die vorlaufenden Nullen bei
nicht dreistelligen Zahlen, dann wird alphanumerisch sortiert und doppelte
Zeilen entsorgt (ginge hier auch direkt mit sort -u) und zuletzt nehme ich
die überflüssigen Punkte und Nullen wieder raus.
Das ganze mache ich unter Debian, mag sein das andere Linuxe und Unices
anders arbeiten.
hth
Günter
"Günter Frenz" schrieb:
> ...
> Dies macht zwar das was ich erreichen will, aber ich denke das es auch
> noch
> andere (kürzere) Lösungen gibt. Vorschläge?
Mit Lex und Awk. Man braucht nur einen einzigen regulaeren ausDruck, um
eine typische IP# zu parsen. Dann steht sie in yytext drin. Darinnen durch
eine
C-Loop alle Punkte durch LeerZeichen ersetzen. Das auf stdout raus.
In Awk reinpipen. Mit printf diese vier Felder wieder formatiert raus,
bei gefallen auch wieder mit Punkten. Das in sort rein. Fertig.
Mmh - Bloss die Punkte aus einer IP# zu extrahieren - das ist eine
Zeile sed - da kann man sich den Lex schenken. Dann weiter mit Awk wie
eben beschrieben.
MHO. HTH.
Herwig
Ich schrieb:
> ...
> Mmh - Bloss die Punkte aus einer IP# zu extrahieren - das ist eine
> Zeile sed - da kann man sich den Lex schenken. Dann weiter mit Awk wie
> eben beschrieben.
Guck mal:
$ for Q1 in 53 23 ; do for Q2 in 134 14 ; do for Q3 in 179 19 2 ; do for Q4
in 89 88 ; do echo ${Q1}.${Q2}.${Q3}.${Q4} | sed -e 's/\./ /g' | awk '{
printf "%03i.%03i.%03i.%03i\n", $1, $2, $3, $4 } ' ; done; done ; done ;
done | sort
023.014.002.088
023.014.002.089
023.014.019.088
023.014.019.089
023.014.179.088
023.014.179.089
023.134.002.088
023.134.002.089
023.134.019.088
023.134.019.089
023.134.179.088
023.134.179.089
053.014.002.088
053.014.002.089
053.014.019.088
053.014.019.089
053.014.179.088
053.014.179.089
053.134.002.088
053.134.002.089
053.134.019.088
053.134.019.089
053.134.179.088
053.134.179.089
Wenn es das ist, was Du willst - das Geschenk zum Nikolaus.
Herwig
Du meintest am 06.12.05:
> nach dem grep und cut erhalte ich eine Liste in der folgenden
> Bauart:
> 217.91.37.7
> 87.78.52.97
> 87.78.55.70
> 201.9.24.235
Prinzip der Sortierung:
a) Option "-n"
b) Spalten- oder Feldtrenner ist der Punkt
Viele Grüße!
Helmut Hullen
BS
ger.ct - das gallige Dorf im Usenet
> Hallo, Günter,
>
> Du meintest am 06.12.05:
>
>> nach dem grep und cut erhalte ich eine Liste in der folgenden
>> Bauart:
>
>> 217.91.37.7
>> 87.78.52.97
>> 87.78.55.70
>> 201.9.24.235
>
> Prinzip der Sortierung:
> a) Option "-n"
> b) Spalten- oder Feldtrenner ist der Punkt
sowas habe ich ja schon versucht (siehe erster Post), das wäre ja etwas in
der Art:
sort -n -t "."
Dabei wird auf meinem System die 213.121.151.162 hinter der 213.196.212.94
einsortiert, was ja eigentlich umgekehrt sein sollte.
oder meinst du was anderes?
Günter
> 2005-12-06 18:14:10 MEZ
>
> Ich schrieb:
>
>> ...
>> Mmh - Bloss die Punkte aus einer IP# zu extrahieren - das ist eine
>> Zeile sed - da kann man sich den Lex schenken. Dann weiter mit Awk wie
>> eben beschrieben.
>
> Guck mal:
>
> $ for Q1 in 53 23 ; do for Q2 in 134 14 ; do for Q3 in 179 19 2 ; do for
^^^^^ ^^^^^^ ^^^^^^^^
Ich sehe hier das Problem, dass ich ja vorher nicht weiß, welche Nummern in
den Spalten auftauchen. Die IPs stammen ja aus einem realen Logfile.
> Q4 in 89 88 ; do echo ${Q1}.${Q2}.${Q3}.${Q4} | sed -e 's/\./ /g' | awk '{
> printf "%03i.%03i.%03i.%03i\n", $1, $2, $3, $4 } ' ; done; done ; done ;
> done | sort
[...]
> Wenn es das ist, was Du willst - das Geschenk zum Nikolaus.
Dazu hättest du das aber gestern Abend schon in meinen Stiefel stecken
müssen...
Günter
> Herwig Huener wrote:
>
>> 2005-12-06 18:14:10 MEZ
>>
>> Ich schrieb:
>>
>>> ...
>>> Mmh - Bloss die Punkte aus einer IP# zu extrahieren - das ist eine
>>> Zeile sed - da kann man sich den Lex schenken. Dann weiter mit Awk wie
>>> eben beschrieben.
>>
>> Guck mal:
>>
>> $ for Q1 in 53 23 ; do for Q2 in 134 14 ; do for Q3 in 179 19 2 ; do for
> ^^^^^ ^^^^^^ ^^^^^^^^
> Ich sehe hier das Problem, dass ich ja vorher nicht weiß, welche Nummern in
> den Spalten auftauchen. Die IPs stammen ja aus einem realen Logfile.
Nunja das könnte man ja durch nen Skript dynamisch erzeugen, aber wieso so
viel Aufwand? Problem das Dein Sort nicht geht ist vermutlich die fehlende
führende Null (Bug in sort?). Da Du aber Schalter n benutzt müsste es ohne
diese ominöse Null gehen. Vermutlich arbeitet sort aber dennoch nicht im
Numeric-Modus, also einfach führende Null hinzufügen und später wenn's stört entfernen.
cat ipliste | sed 's/\./ /g' | gawk '{printf("%03d %03d %03d %03d\n", $1,$2,$3,$4)};' | sort -n -t " " | gawk '{printf("%d.%d.%d.%d\n",$1,$2,$3,$4);}'
würde sowas hier ergeben:
81.173.163.16
81.173.172.69
84.44.214.75
87.78.46.132
87.78.52.97
87.78.55.70
195.14.205.35
195.14.207.70
195.14.218.198
195.14.223.213
201.9.24.235
201.19.143.97
201.42.181.117
213.5.31.195
213.28.164.61
213.140.241.33
213.168.108.73
213.168.111.14
213.196.195.9
213.196.252.3
217.91.37.7
Wenn es auch mit führender Null geht, wäre der Ausruck noch etwas kürzer:
cat ipliste | sed 's/\./ /g' | gawk '{printf("%03d.%03d.%03d.%03d\n", $1,$2,$3,$4)};' | sort -n -t "."
würde sowas ergeben:
081.173.163.016
081.173.172.069
084.044.214.075
087.078.046.132
087.078.052.097
087.078.055.070
195.014.205.035
195.014.207.070
195.014.218.198
195.014.223.213
201.009.024.235
201.019.143.097
201.042.181.117
213.005.031.195
213.028.164.061
213.140.241.033
213.168.108.073
213.168.111.014
213.196.195.009
213.196.252.003
217.091.037.007
Müsste also auch ohne Schalter "-n" beim sort gehen, kannst es ja testen.
Richtig toll finde ich den Ausdruck aber immer noch nicht. Kannst ja mal
die gleiche Frage in dclpm stellen, die bekommen dat bestimmt noch kürzer
hin ;-)
[...]
> Dazu hättest du das aber gestern Abend schon in meinen Stiefel stecken
> müssen...
mfg
Er*nachträglich in Deinen Stiefel stopf*ik
> Nunja das könnte man ja durch nen Skript dynamisch erzeugen, aber wieso so
> viel Aufwand? Problem das Dein Sort nicht geht ist vermutlich die fehlende
> führende Null (Bug in sort?). Da Du aber Schalter n benutzt müsste es ohne
> diese ominöse Null gehen. Vermutlich arbeitet sort aber dennoch nicht im
> Numeric-Modus, also einfach führende Null hinzufügen und später wenn's
> stört entfernen.
>
> cat ipliste | sed 's/\./ /g' | \
> gawk '{printf("%03d %03d %03d %03d\n",$1,$2,$3,$4)};' | \
> sort -n -t " " | gawk '{printf("%d.%d.%d.%d\n",$1,$2,$3,$4);}'
ich habe da mal ein paar Backslashes ergänzt damit die Zeilenbreite passt.
Dein Vorschlag funktioniert bei sort auch ganz ohne Parameter (jedenfalls
bei mir). Ansonsten ist das ja der Ansatz,l den ich auch in meiner Version
verfolgt habe, nur das ich das Ergänzen der führenden Nullen mit sed
verbrochen habe. Deine Version ist da schon ein wenig angenehmer zu lesen.
> Richtig toll finde ich den Ausdruck aber immer noch nicht. Kannst ja mal
> die gleiche Frage in dclpm stellen, die bekommen dat bestimmt noch kürzer
> hin ;-)
mal sehen was noch kommt...
Günter
LC_ALL=C sort bla < list
Grüße, Hansjörg
Du meintest am 06.12.05:
> sort -n -t "."
> Dabei wird auf meinem System die 213.121.151.162 hinter der
> 213.196.212.94 einsortiert, was ja eigentlich umgekehrt sein
> sollte.
Nicht reproduzierbar.
Könnte sein, dass Du mit den Variablen herumspielen musst, die z.B.
per "locale" angezeigt werden.
Oft reicht schon "LC_ALL=C" vorm eigentlichen Programmaufruf.
das hilft nur bei den ersten beiden Oktetten. Nach dem 2. Punkt wird es auch
dann nicht mehr als Zahl interpretiert:
LC_ALL=C sort -n < testsort.orig | uniq
liefert unter anderem dieses:
213.168.233.180
213.168.233.19
213.168.72.249
Günter
Habs mal nach dclpm gepostet (<4396147...@nurfuerspam.de>), mal sehen was
die RegExp-Guru's draus machen ;-)
Wollen wir Wetten abschließen wie lang die kürzeste Zeile ist? Ich
sage jetzt mal 80 Zeichen, wer bietet weniger?
mfg
Erik
LC_ALL=C sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n < list
Grüße, Hansjörg
Günter Frenz wrote:
> ...
> Ich sehe hier das Problem, dass ich ja vorher nicht weiß, welche Nummern in
> den Spalten auftauchen. Die IPs stammen ja aus einem realen Logfile.
Ich habe die aeusseren vier Schleifen nur gemacht, um ein
paar SpielDaten zu haben.
Herwig (morning reboot)
--
**********************************************************
* http://www.quantenrente.de Josella Simone Playton *
* http://www.Josella-Simone-Playton.de Herwig Huener *
**********************************************************
> LC_ALL=C sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n < list
das sieht gut aus, geht dann auch ohne geänderte LC_ALL.
Allerdings kann ich diese Syntax nicht aus der spärlichen manpage von sort
herauslesen. Hast du Quellen, wo man mehr darüber lesen kann?
Günter
Ich bin zugegebenermaßen manchmal zu faul, mir zu überlegen, ob mir in
einem bestimmten Fall die Locale ausnahmsweise mal nicht in die Quere
kommt. Bei Ganzzahlen ohne Tausender-Trennzeichen kann man aber wohl
zuversichtlich sein, keine unerwarteten Ergebnisse zu erhalten :-/
> Allerdings kann ich diese Syntax nicht aus der spärlichen manpage von sort
> herauslesen. Hast du Quellen, wo man mehr darüber lesen kann?
info sort
http://www.opengroup.org/onlinepubs/009695399/utilities/sort.html
http://www.opengroup.org/onlinepubs/009695399/download/
Nacht, Hansjörg
Du meintest am 07.12.05:
info sort
oder (komfortabler)
pinfo sort
"Erik Griffin" schrieb:
> Wollen wir Wetten abschließen wie lang die kürzeste Zeile ist? Ich
> sage jetzt mal 80 Zeichen, wer bietet weniger?
Ich. Also das reine Extrahieren sieht mit lex so aus:
---------------------------------------------------------------------------------
%%
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} printf ("%s\n", yytext);
.
\n
---------------------------------------------------------------------------------
Danach mit sed die Punkte entfernen, mit awk die EinzelZahlen auf
0..255 pruefen und formatiert ausgeben, danach sort, wie gehabt.
Dieser Lexer holt die IP# aus einem beliebigen unformatierten
ZeichenMatsch heraus.
Herwig
"Günter Frenz" schrieb:
> hier haben sich ja schon wiederholt einige als wahre Meister der
regulären
> Ausdrücke und deren Nutzung in grep, sed, etc. gezeigt. Ich hätte da eine
> Aufgabe, für deren Lösung mir nur eine sehr monströse Pipeline eingefallen
> ist:
> ...
Da es in dieser NG heimlich mitledende BS2000-Fans gibt, waere die
ketzerische
Frage angebracht, wie man diese Aufgabe mit den "BordMitteln" des BS2000
loest.
Achtung: Verwendung von Posix gildet nicht!
Herwig
Günter Frenz wrote:
> ...
Ich habe jetzt einmal, durch diesen Thread angeregt,
mir drei kleine Tools gestrickt, die an der Grenze zur
Nuetzlichkeit sind: "qemail", "qurl" und "qip". Die
tun nichts weiter als irgendetwas von stdin einizuschaufeln
und Zeile fuer Zeile alle email-adressen, Webadressen
oder IP# auf stdout auszugeben. Mit KommandoZeilenoption
auf Wunsch mit laufender Nummer geprefixed, oder
eine VierZeilen-Help-funktion.
Der AufWand war minimal - 3 * 23 Zeilen flex
und 8 + 85 Zeilen C - dabei die Haelfte LeerZeilen
wegen der Uebersichtlichkeit:
$ wc *.l *.h *.c
23 25 585 qemail.l
23 25 585 qip.l
23 25 585 qurl.l
8 23 171 common.h
85 204 1741 common.c
1527 5140 36601 qemail.c
1530 5177 36814 qip.c
1531 5190 36906 qurl.c
4750 15809 113988 insgesamt
(Die fuenfzehnhundert Zeilen C-Programme ist
das, was flex generiert hat.)
Abgesehen von ProgrammierFehlern - was sollten diese
WinzTools sonst noch koennen? Wie in Unix ueblich
kann man ja fast alles erreichen, indem man den
Output in andere Utilities hinein-piped. Kann doch
nicht sein, dass das Konzept schon perfekt ist!
Fuer "qip" (IP#-Extractor) ist meine WarteListe:
Pruefen auf Groesse der Zahlen zwischen 0 und 255,
Auf Wunsch Ausgabe drei+drei+drei+dreistellig,
wegen Sortierung, vielleicht auch AusGabe in Hex,
und natuerlich, wenn mich das ganz intensive
Beduerfnis befaellt, auch Behandlung von IPV6.
Fuer "qurl" denke ich an die wahlweise Entfernung
von semantik-freien URL-Anteilen, und https:// und
ftp:// sollte er auch erkennen koennen. (lynx -dump
laesst gruessen!)
Fuer "qemail" (email-Adressen-Extractor) faellt mir
ueberhaupt kein ErweiterungsWunsch ein, der nicht
mit anderen Unix-WerkZeugen zu erledigen waere.
BTW: Unix ist ueberhaupt eine herbe Geliebte.
Jahrelang habe ich mich gefragt, warum es zwar
ein "tail"-Programm gibt, aber kein "head" Programm.
Wisst ihr's? Jetzt irgendwo gelesen: "sed '10 q' "
ist die Antwort. Haette man selber drauf kommen
koennen.
Herwig
Ich hab zwar jetzt nur Cygwin vor mir und dort existiert es:
$ head --help
Usage: head [OPTION]... [FILE]...
Print the first 10 lines of each FILE to standard output.
With more than one FILE, precede each with a header giving the file name.
With no FILE, or when FILE is -, read standard input.
Mandatory arguments to long options are mandatory for short options too.
-c, --bytes=[-]N print the first N bytes of each file;
with the leading `-', print all but the last
N bytes of each file
-n, --lines=[-]N print the first N lines instead of the first 10;
with the leading `-', print all but the last
N lines of each file
-q, --quiet, --silent never print headers giving file names
-v, --verbose always print headers giving file names
--help display this help and exit
--version output version information and exit
N may have a multiplier suffix: b 512, k 1024, m 1024*1024.
Report bugs to <bug-co...@gnu.org>.
--
Oliver
"Oliver Vecernik" schrieb:
> ...
> Ich hab zwar jetzt nur Cygwin vor mir und dort existiert es:
>
> $ head --help
Tatsaechlich - auf meinem CygWin auch.
Die beschriebene Funktionalitaet wuerde natuerlich schon ein
kleines Script bedeuten, weil es ueber den sed-EinZeiler hinausgeht.
Es scheint aber ein richtiges executable zu sein. Vielleicht aus
Performance-Gruenden.
Herwig
FreeBSD hat ein head seit 1994.
http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/head/head.c
Weiter reicht die CVS-History nicht, weil das damals aufgesetzt wurde.
Und importiert wurde es aus BSD 4.4 Lite, dessen Wurzeln bis in die
Siebziger zurückreichen. Ein Blick in die Quellen zeigt
| /*
| * head - give the first few lines of a stream or of each of a set of files
| *
| * Bill Joy UCB August 24, 1977
| */
Was benutzt Du eigentlich für ein Unix? Oder ist das so alt, dass es
sich noch nichtmal bei BSD bedeinen konnte? :-)
Hm, wie alt ist eigentlich sed?
Mal sehen, bsd-sed kommt nach
http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/sed/main.c auch aus
BSD 4.4 Lite, aber das älteste Copyright ist von 1992. Gnu-sed ist
wahrscheinlcih älter, oder?
Hilko
Hilko Meyer wrote:
> ...
> Was benutzt Du eigentlich für ein Unix? Oder ist das so alt, dass es
> sich noch nichtmal bei BSD bedeinen konnte? :-)
Also historisch ist das so gelaufen, dass ich bei der
Lektuere irgendeines Textes ueber "sed" las, dass diese
eine Zeile ein "head" implementiert. Da ich bis dahin "head"
nie gebraucht hatte - ein "view" mit mehreren DateiArgumenten
ist genauso gut - nahm ich dann an, dass es keins gibt,
eben aus dem Grunde der leichten Ersetzbarkeit durch "sed".
Deshalb habe ich auch fuerderhin nie danach gesucht.
Jetzt sehe ich: Es wimmelt von "head"s.