Archiv verlassen und diese Seite im Standarddesign anzeigen : sed- und REGEX-Spezialist gesucht, zwecks Erklärung
Hi,
die Verwendung von regulären Ausdrücken verwirrt mich ein wenig.
Das Problem ist schon gelöst aber es hätte auch anders gehen müssen.
String:
$neu_passwort = '4sdfsdsHHX';
Funktioniert hat:
sed -r 's/.+ = .{1}([0-9a-zA-Z]*).{2}/\1/'
Im Detail:
-------
-r extended Regex
------
.+ = .{1} ---> beliebiges Zeichen (.), welches beliebig oft vor kommt (+) gefolgt vom Whitespace, einem Gleichheitszeichen und noch einem Whitespace. Dies wiederum gefolgt von einem beliebigen Zeichen welches nur einmal vorkommt.
Entspricht:
$neu_passwort = '
([0-9a-zA-Z]*).{2} --> Suchmustergruppe "( )" mit der Menge "[ ]" von allen Zahlen und Buchstaben, welche keinmal oder beliebig oft in beliebiger Reihenfolge vorkommen "*". Gefolgt von beliebigen Zeichen, welches 2 mal
vorkommt.
Entspricht:
4sdfsdsHHX';
/\1/ --> Ersetze erstes Suchmuster durch Fund in Suchmustergruppe 1.
Also
$neu_passwort = '4sdfsdsHHX';
wird geparst und das eigentliche Passwort entspricht der Suchmustergruppe 1.
Der komplette Ursprungsstring wird überschrieben mit Suchmustergruppe 1.
Ergebnis:
4sdfsdsHHX
Jetzt die Verständnisfrage :)
Warum kann es nicht wie folgt aussehen?
sed -r 's/.*.{1}([0-9a-zA-Z]+).{2}/\1/'
Gibt nur X aus
Als Erklärung würde ich das wie folgt schreiben:
beliebiges Zeichen, was keinmal oder mehrfach vorkommen kann,
bis zu dem Zeichen, welches nur einmal vorkommen darf VOR der Suchmustergruppe,
welche nur aus Buchstaben und Zahlen besteht und jedes erlaubte zeichen einmal oder öfter vorkommen darf,
gefolgt von 2 weiteren beliebigen Zeichen.
Meines Erachtens, trifft das genau auf den String zu und nach meinem Verständnis müsste es mir das komplette passwort ausgeben.
4sdfsdsHHX
Warum wird nur dann, wie oben erklärt nur das X ausgegeben?
Beschreibe doch bitte erstmal in klaren deutschen Sätzen was du vorhast. Dann wird es auch für Ausstehende verständlich.
Du postest die Lösung des 'Problems' und willst eine Alternativlösung, - ohne das 'Problem' zu beschreiben.
Du willst also wissen, warum die beiden Regex
.+ = .{1}([0-9a-zA-Z]*).{2}
und
.*.{1}([0-9a-zA-Z]+).{2}
für die Zeile
$neu_passwort = '4sdfsdsHHX';
nicht äquivalent sind?
Schau' dir einfach den 2. Regex an:
.*.{1} Beliebig viele beliebige Zeichen, gefolgt von einem beliebigen Zeichen. Das entspricht 1. schonmal .+ und matcht 2. zu viel von deinem String. Nämlich einfach alles was als drittletztes Zeichen eine Ziffer oder einen Buchstaben hat.
Da liegt das Problem. Woher soll die Engine wissen, wie viel von .*.{1} und wieviel von ([0-9a-zA-Z]+) gematcht werden soll? Das erste kann nämlich ganz locker das zweite mitmatchen, wegen der Beliebigkeit. Und da wird scheinbar einfach nur ein Zeichen aus ([0-9a-zA-Z]+) übrig gelassen, damit der Regex überhaupt zutreffen kann. -> X
Ich denke man sollte Regex so weit einschränken wie möglich, nicht das mehr/anders gematcht wird als vorgesehen.
.*.{1} Beliebig viele beliebige Zeichen, gefolgt von einem beliebigen Zeichen. Das entspricht 1. schonmal .+ und matcht 2. zu viel von deinem String. Nämlich einfach alles was als drittletztes Zeichen keine Ziffer oder einen Buchstaben hat.
Das markierte gilt für den gesamten Ausdruck, irgendwie hätte der Satz nicht dahin gesollt, denkt ihn euch bitte als vorletzten Satz...
Und dann wollte ich noch dem Gast aus #2 Zustimmen. Für möglichst genaue Hilfe solltest du genauer beschreiben was du tun willst. Dein erster Regex matcht nämlich ziemlich viele Zuweisungen, z.B. auch $foo = $bar;. Ergebnis sollte hier ba sein, wenn ich mich jetzt nicht irre.
Also Vorsicht!
Ich hätte es schreiben sollen, was das ziel ist.
Ziel ist es das Passwort als reinen String zu bekommen.
Ich finde das ist aber aus dem Kontext erkennbar.
Post #3 muss ich mir mal durch den Kopf gehen lassen.
@Post #4
Ich habe ja vorgegeben was ich parsen will. Diese eine Zeile in dieser Form, die sich auch nicht ändern wird.
Was alles drum herum ist und damit zusammen hängt ist egal.
P.S.
echo "\$foo = \$bar" | sed -r 's/.+ = .{1}([0-9a-zA-Z]*).{2}/\1/'
b
aber dafür wars ja auch nicht gedacht. ;)
Ziel ist es das Passwort als reinen String zu bekommen.
Ich finde das ist aber aus dem Kontext erkennbar.
@Post #4
Ich habe ja vorgegeben was ich parsen will. Diese eine Zeile in dieser Form, die sich auch nicht ändern wird. Dir ist das sicher klar. Aber wir wissen eben nicht ob das wirklich die einzige Zeile ist die du finden willst oder ob du nur exemplarisch ein Beispiel anführst oder gar gleich etwas leicht verändertes um keinen Code zu verraten.
P.S.
echo "\$foo = \$bar;" | sed -r 's/.+ = .{1}([0-9a-zA-Z]*).{2}/\1/'
ba
aber dafür wars ja auch nicht gedacht. ;)
Nun ich dachte mir halt, dass wenn man Sourcen damit bearbeitet die dutzende, evtl. sogar hunderte Zuweisungen machen, es nicht gewünscht ist, neben dem gesuchten Output viel Unsinn zu haben.
Sicher ist sicher :)
Wenn das Suchmuster aber so genau zu bestimmen ist, dann kann man den Ausdruck auch extrem einschränken:
sed -r "s/\\\$neu_passwort = '([0-9a-zA-Z]*)';/\1/"
Von \\\$ lässt die Shell (also Bash zumindest) \$ übrig, woraus sed dann $ macht, mehrfach escapen ist leider enorm undurchsichtig...
@#44
hast ja recht. ^^ ich hätte es erst mal genau beschreiben sollen was ich machen will.
Sollte jetzt geklärt sein. :)
Auch wenn man nen kompletten sourcecode durchgehen würde, haste recht.
Allerdings grep ich da vorher diese eine zeile raus, so das nur noch die bearbeitet werden muss.
Ist dann zwar doppelt gemoppelt, wenn man danach das ganze mit sed weiter runterbricht, aber das ist kein script, was performant sein muss. ^^
Deine Zeile funktioniert sehr gut.
echo "\$neu_passwort = '4sdfsdsHHX';" | sed -r "s/\\\$neu_passwort = '([0-9a-zA-Z]*)';/\1/"
4sdfsdsHHX
Ich hatte probleme mit dem maskieren der einfachen anführungszeichen, innerhalb des Suchmusters. Deswegen hatte ich die auch versucht mit REGEX zu bestimmen.
Auf die idee, das ganze sed-script in doppelte Anführungszeichen zu setzen um dann einfache Anführungszeichen innerhalb des Scripts zu verwenden, bin ich nicht gekommen. -.-
Wieder was dazu gelernt. :)
Also danke.
Deine Zeile funktioniert sehr gut.
echo "\$neu_passwort = '4sdfsdsHHX';" | sed -r "s/\\\$neu_passwort = '([0-9a-zA-Z]*)';/\1/"
4sdfsdsHHX
Ich hatte probleme mit dem maskieren der einfachen anführungszeichen, innerhalb des Suchmusters. Deswegen hatte ich die auch versucht mit REGEX zu bestimmen.
Auf die idee, das ganze sed-script in doppelte Anführungszeichen zu setzen um dann einfache Anführungszeichen innerhalb des Scripts zu verwenden, bin ich nicht gekommen. -.-
Wieder was dazu gelernt. :)
Also danke.
Ich habe auch erst versucht ' zu escapen. Single-quotes verschachteln kann Bash nicht. Ergibt nen syntax error. Das habe ich aber auch erst verstanden, als ich eine Seite über Bash-Escapes zwecks Lösung ohne quotes gefunden hatte...
Also bleiben double-quotes, oder keine quotes. Ohne quotes muss man noch mehr escapen (u.a. whitespaces und ; ) -> Unlesbar -> double-quotes.
Wenn man mit double-quotes das $ nicht richtig escaped kommt die komplette echo Zeile als Ausgabe, da sed wohl wegen dem fehlenden $ nichts ma(t)cht.
€: Das hängt alles mit der unterschiedlichen Bedeutung von no/single/double-quotes in Bash (http://www.gnu.org/software/bash/manual/bashref.html#Quoting) zusammen.
Ich habe also genau so viel gelernt wie du
:freak:
vBulletin®, Copyright ©2000-2024, Jelsoft Enterprises Ltd.