Hallo zusammen, kann mir mal jemand "aus dem Handgelenk heraus" einen kurzen Text-Ersetzungs-Einzeiler zur Verfügung stellen? Das geht sicherlich mit awk oder sed und einen bash-Einzeiler, aber ich möchte jetzt nicht erst mal 1/2 Stunde rumfummeln ... gegeben ist eine (ziemlich umfangreiche) Logdatei [logdatei.txt]. Diese enthält schwer lesbare [*1] Logeinträge, welche ich bei Schlüsselworten ergänzen möchte. Diese Schlüsselworte stehen in einer weiteren Datei [ersetzungen.txt] [*1] Die Logdatei enthält natürlich nicht so einen Quatschtext wie unten im Beispiel aufgelistet. Es sind umfangreiche technische Informationen. Die Schlüsselworte sind Funktionsaufrufe, die sind aber vom Namen her relativ "kryptisch", und sollen durch besser lesbaren, und direkt ins Auge springenden Text (daher die [*** . ***] Umhüllung) ersetzt werden. Die Quelldatei liegt auf einer Linux Maschine vor, die Ersetzungen könnten auf der Linux Maschine oder unter Windows10 passieren (reines Windows, kein cygwin o.ä. drauf vorhanden) Beispiel: logdatei.txt oh wie schön ist doch diese pqrz Wolke der gvra Fluss ist recht lang Hier steht was zur Farbe ogqa ersetzungen.txt "pqrz","blau" "gvra","gelb" "ogqa","grün" logdatei_neu.txt oh wie schön ist doch diese [*** blau ***] pqrz Wolke der [*** gelb ***] gvra Fluss ist recht lang Hier steht was zur Farbe [*** grün ***] ogqa
:
Bearbeitet durch User
Wenn Du auf ersetzungen.txt verzichten kannst:
1 | sed 's/pqrz/blau/g' < logdatei.txt | |
2 | sed 's/gvra/gelb/g' | |
3 | sed 's/ogqa/grün/g' > logdatei_neu.txt |
Mit so einer Beschreibungsdatei ersetzungen.txt wird es ungleich komplizierter.
leider kann ich auf ersetzungen.txt nicht verzichten. es sind ca. 100 Einträge in dieser Datei, die sich auch noch dynamisch verändern (ergänzen) ausserdem soll ja der ursprüngliche Text, UND der neue Text, nachher vorhanden sein, siehe oben im Beispiel logdatei_neu.txt
:
Bearbeitet durch User
Deine ersetzung.txt muss folgendes enthalten: s/pqrz/blau/g s/gvra/gelb/g s/ogqa/grün/g dann sed -f ersetzungen.txt < logdatei.txt
Wegstaben V. schrieb: > leider kann ich auf ersetzungen.txt nicht verzichten. es sind ca. 100 > Einträge in dieser Datei, die sich auch noch dynamisch verändern > (ergänzen) Dann nimm die Lösung von jobi. > ausserdem soll ja der ursprüngliche Text, UND der neue Text, nachher > vorhanden sein, siehe oben im Beispiel logdatei_neu.txt Wenn Du oben nochmal nachliest, steht da "> logdatei_neu.txt". Die alte Datei bleibt also erhalten. sed verändert die ursprüngliche Datei nicht.
:
Bearbeitet durch Moderator
Deine ersetzungen.txt sollte dann eben so aussehen: s/pqrz/[*** blau ***] &1/g s/gvra/[*** gelb ***] &1/g s/ogqa/[*** grün ***] &1/g dann sed -f ersetzungen.txt < logdatei.txt oh wie schön ist doch diese [*** blau ***] pqrz1 Wolke der [*** gelb ***] gvra1 Fluss ist recht lang Hier steht was zur Farbe [*** grün ***] ogqa1
1 | sed 's|"\(.*\)","\(.*\)"|s/\1/\[*** \2 ***] \1/g|' ersetzungen.txt | sed -f - logdatei.txt > logdatei_neu.txt |
nebenbei betreffend Einzeiler: eine geniale Quelle ist auch https://www.commandlinefu.com/commands/browse
An dem Punkt wo man auf der shell zu Metaprogrammierung greift wäre meine persönliche Obfuskations-Schmerzgrenze schon überschritten. Das wär mir zu Meta wie man so schön sagt. Ich würde mir stattdessen völlig direkt ein kleines Python-Script zusammenklöppeln das dann zwar aus wesentlich mehr (kürzeren) Zeilen besteht, dafür aber extrem lesbar, wartbar und selbsterklärend wäre.
Bernd K. schrieb: > Das wär mir zu Meta wie man so schön sagt. Wenn man Regular Expressions versteht, erscheint Yalus Zeile doch sehr einfach und genial. Der erste sed-Aufruf baut aus der Ersetzungstabelle die Ersetzungsbefehle für den zweiten sed zusammen. Fertig. Da ist nix magisches dran.
Möchtest du mit deinen Ersetzungen etwa Wegstaben verbuchseln?
Frank M. schrieb: > Bernd K. schrieb: >> Das wär mir zu Meta wie man so schön sagt. > > Wenn man Regular Expressions versteht, erscheint Yalus Zeile doch sehr > einfach und genial. Längere Regexes sehen halt meist etwas kryptisch aus. Selbst ein Profi muss sie Zeichen für Zeichen durchgehen, um zu erkennen, was da genau geschieht. Wenn man das Ganze in Python schreibt, würde man wahrscheinlich ebenfalls Regexes benutzen, um sich das Leben etwas zu erleichtern, nur würde man nicht versuchen, alles in eine Zeile zu quetschen. Aber auch in einem Shell-Skript steht es einem frei, den Code auf mehrere Zeilen zu verteilen bspw. so:
1 | # Regex für die Konvertierung der Ersetzungsliste in sed-Kommandos |
2 | search='"\(.*\)","\(.*\)"' |
3 | replace='s/\1/\[*** \2 ***] \1/g' |
4 | ers2sed="s|$search|$replace|g" |
5 | |
6 | sed "$ers2sed" ersetzungen.txt | # Konvertieren der Erstzungsliste |
7 | sed -f - logdatei.txt > logdatei_neu.txt # Ausführen der sed-Kommandos |
Damit wird die Regex in zwei logisch sinnvolle Teile zerlegt und vom weniger kryptischen Rest getrennt sowie jedem der beiden sed-Kommandos eine eigene Zeile zugestanden. Natürlich sind auch Kommentare selten ein Fehler.
Yalu X. schrieb: >
1 | > sed 's|"\(.*\)","\(.*\)"|s/\1/\[*** \2 ***] \1/g|' ersetzungen.txt | sed |
2 | > -f - logdatei.txt > logdatei_neu.txt |
3 | > |
Anstelle von ANFÜHRUNGZEICHEN - BELIEBIGE ZEICHEN - SCHLUSSZEICHEN vereinfache ich jeweils auf ANFÜHRUNGSZEICHEN - ALLES AUSSER SCHLUSSZEICHEN - SCHLUSSZEICHEN. Lieber wäre mir hier der ERE/PCRE Quantifier + (mindesten ein...) anstelle von * (kein oder mehrere...), aber ich war bisher zu faul herauszufinden ob möglich und wie man das bei sed einsetzt <:-)
1 | "[^"]*" # Gruppenklammerung ausgelassen |
2 | |
3 | "[^"]+" # PCRE |
Hans schrieb: > Möchtest du mit deinen Ersetzungen etwa Wegstaben verbuchseln? nein, es sind Logeinträge "in etwa" wie diese: 12:23:14 Info call sub_chk3 das soll dann werden zu 12:23:14 Info call [*** Checkroutine zur Füllstandsüberprüfung ***] sub_chk3
Frank M. schrieb: > Da ist nix > magisches dran. Kryptische Shell Befehle sind eine Sache, aber kryptische Shell-Befehle die kryptische Shell-Befehle generieren und dann ausführen ist mir persönlich halt eine Stufe zu Meta. Aber das scheint wohl Geschmackssache zu sein, jeder hat ne andere Definition von schönem Code.
Bernd K. schrieb: > Kryptische Shell Befehle sind eine Sache, aber kryptische Shell-Befehle > die kryptische Shell-Befehle generieren [...] Es werden keine Shell-Befehle generiert, lediglich reguläre Ausdrücke für sed. > Aber das scheint wohl > Geschmackssache zu sein, jeder hat ne andere Definition von schönem > Code. Schreibe es doch mal klassisch auf, z.B. in schnödem C. Dann kann man ja nochmal vergleichen, was "schöner" ist ;-)
Bernd K. schrieb: > ist mir persönlich halt eine Stufe zu Meta. Das verstehe ich. Wenn man sich aber daran gewöhnt, sind die Vorteile immens: Die beiden Schritte sind jeweils einfach und (durch das eigenständige Zwischenergebnis) nachvollziehbar. Wenn es hakt, sieht man sofort, in welchem Schritt. Die Adaption an andere Ersetzungs-files ist genauso einfach wie an andere Ausgabenformate. Jeder Schritt kann einzeln probiert, verändert werden. Du brauchst keine aufwendige Compiler-collection. Als Debugger reichen Pause und Echo. Wenn Du ein monolithisches Script draus machst, dann scheint es einfacher, weil die Komplexität von unnötigem trivialen Ballast umgeben ist. Das größere Problem ist aber, dass das zwischenergebnis quasi nur virtuell vorliegt und deshalb Debugger, Datenstrukturen, Architektur notwendig werden.
Frank M. schrieb: > Schreibe es doch mal klassisch auf, z.B. in schnödem C. C würd ich nicht nehmen sondern eher irgendeine Scriptsprache die eh schon installiert ist weil sie zufällig für anderes auch genutzt wird.
A. S. schrieb: > Das größere Problem ist aber, dass das zwischenergebnis quasi nur > virtuell vorliegt und deshalb Debugger, Datenstrukturen, Architektur > notwendig werden. In dem Fall des Einzeilers ist das Zwischenergebnis nur "virtuell" vorhanden (in der Pipe), meinst Du das? Um das Zwischenergebnis zu begutachten muss ich den Befehl zerlegen. Im Script kann ich mir das mit nem print() schnell ausgeben lassen, Debugger muss ich dafür nicht gleich auffahren. Aber ich will da auch jetzt nicht groß drauf rum reiten, ich wollte nur meine persönliche Meinung kundtun, ich finde die Syntax häßlich und auch wenn es unbestritten von der Idee her elegant ist ist es letzten Endes keineswegs schön, zumindest nicht in meinen Augen.
:
Bearbeitet durch User
irgendie klappts doch nicht mit dem ersten "Search" Teil des sed Kommandos. Ok, meine Anforderungen haben sich ein wenig verändert, ich hatte gehofft, das ich das mit kleinen Anpassungen selbst hinbekomme. Zuer Erläuterung: die ersetzungen.txt kommt als Export aus Excel als csv Datei. "c" heisst bei Excel aber Semikolon. Und auch die Gänsefüsschen zur Umklammerung der einzelnen Felder gibt es nicht. Irgendwelche Makros, welche das in excel integrieren, sollen nicht eingesetzt werden. Darüber hinaus gibt es nicht 2, sondern 3 Spalten, und manchmal ist Spalte 2 bzw. Spalte 3 nicht belegt. Ich hatte jetzt ich die ursprüngliche "Spezifikation" genommen, die ersetzungen.txt csv Datei entsprechend angepasst. Alle nicht-3-spalten-Einträge wurden rausgelöscht, das Semikolon als Feldtrenner durch Komma ersetzt, udn die einzelnen Felder mit Gänsefüsschen geklammert. Ein Zeileneintrag sieht nun so aus: "Checkroutine zur Füllstandsüberprüfung","Subroutine","sub_chk3" der Aufruf von sed 's|"\(.*\)","\(.*\)","\(.*\)"|s/\1/\[*** \3 ***] \1/g|' ersetzungen.csv | sed -f - quelldatei > zieldatei liefert folgenden Fehler: sed: file - line 2: unknown command: `"'
Wie sieht die Zeile 2 von ersetzungen.csv aus? Entweder weicht dort die Syntax von dieser Vorgabe "Checkroutine zur Füllstandsüberprüfung","Subroutine","sub_chk3" ab, oder die Strings enthalten böse Sonderzeichen. Ich bin bei meinem obigen Lösungsvorschlag der Einfachheit halber davon ausgegangen, dass die Strings keine Sonderzeichen enthalten und habe deswegen auf eine spezielle Behandlung derselben verzichtet. Das ursprüngliche Excel-CSV-Format mit den fehlenden Anführungszeichen und dem Semikolon statt des Kommas könnte mit angepassten Regexes sicher auch von sed verarbeitet werden.
Yalu X. schrieb: > Wie sieht die Zeile 2 von ersetzungen.csv aus? hm, vermutlich ein cr / crlf Problem (ich hatte das "echte" Quellobjekt mittels winscp vom WIn10 Rechner auf die Linux Maschine übertragen, aber dabei den Binärmodus eingestellt gehabt. Jetzt hab ich mal direkt auf der Linux Maschine Dateien angelegt. Es kommt jetzt kein Fehler (mehr), es wird aber auch nix ersetzt. ersetzungen-dummy.txt "Ein wundervolles ersetztes erstes Objekt","hurz","asdf" "auch was schönes","bubu","jklö" quelldatei.txt sdfsf sdfsdf sdfs dfsdf sdfsdfsdf sdfsdf sdf jdjdjdjjd f hurz sdfsdf sfsf sdf sdfsf sdf sdf sf asdad asdf sdf sdf sdfsf sdf sdf sdfsf asdad fsdfsf jklö Befehl sed 's|"\(.*\)","\(.*\)","\(.*\)"|s/\1/\[*** \3 ***] \1/g|' ersetzungen-dummy.txt | sed -f - quelldatei.txt > zieldatei.txt zieldatei.txt sdfsf sdfsdf sdfs dfsdf sdfsdfsdf sdfsdf sdf jdjdjdjjd f hurz sdfsdf sfsf sdf sdfsf sdf sdf sf asdad asdf sdf sdf sdfsf sdf sdf sdfsf asdad fsdfsf jklö
Wegstaben V. schrieb: > Es kommt jetzt kein Fehler (mehr), es wird aber auch nix ersetzt. Logisch, denn es wird nach "Ein wundervolles ersetztes erstes Objekt" und "auch was schönes" gesucht, was beides in quelldatei.txt nicht vorkommt. Du möchtest wahrscheinlich die \1 und \3 im sed-Kommando tauschen. Dann sieht das Ergebnis so aus:
1 | sdfsf sdfsdf sdfs dfsdf sdfsdfsdf sdfsdf sdf |
2 | jdjdjdjjd f hurz sdfsdf sfsf sdf sdfsf sdf sdf sf |
3 | asdad [*** Ein wundervolles ersetztes erstes Objekt ***] asdf sdf sdf sdfsf sdf sdf sdfsf |
4 | asdad fsdfsf [*** auch was schönes ***] jklö |
Die zusätzlichen CRs des DOS-Dateiformats stören bei mir weder in ersetzungen-dummy.txt noch in quelldatei.txt (sed 4.7 unter Linux).
:
Bearbeitet durch Moderator
Bernd K. schrieb: > meinst Du das? Oh, sorry, nein. Ich mach es dann wirklich in 2 (bzw. n) Stufen. Der Einzeiler macht aus der .txt eine batchdatei, die macht dann die Ersetzung (und ggf so weiter). Kommt make auch gut mit klar, und notfalls kann man die batchdatei manuell frisieren, justieren, um neues auszuprobieren bis es klappt und danach den Einzeiler anpassen. Also eher "one Task and ... well".
Yalu X. schrieb: > Dann sieht das Ergebnis so aus: (richtiges Ergebnis) Juhu! Genau so soll es sein. Jetzt schau ich mal, das ich das heraus bekomme, warum die echte Datei rumzickt, und mache die Anpassungen der "neuen Spezifikation". Vorher aber: Prost! Jetzt trinke ich erst mal ein leckeres Kölsch auf dein Wohl!
so, das Kölsch hat geholfen. Die Ursache, warum die Original ersetzungen.txt Datei nicht ging, ist identifiziert: Die berühmte Umlaut-Falle unter Linux hat mal wieder zugeschlagen. z.B. das Wort 'für' (es kommt in meiner Original Datei vor) : Original (als Windows Datei, per winscp auf die Linux Maschine gebracht) 66 fc 72 auf der Linux Maschine erstellte ersetzungen-dummy Datei mit dem Wort 'für' 66 c3 bc 72 der genutzte Editor (xed auf der Linux Maschine) stellt "fieserweise" auf der GUI beides als 'ü' dar. Im Terminal-Fenster auf Linux sieht man jedoch das zerknödelte 'ü' der 8859 Codierung. mit ein bischen Mouse-Over auf dem jeweiligen Tab blendet sich dann sogar beim xed die Zusatzinfo ein: Zeichencodierung: Westlich (ISO-8859-15) -> Windows Datei Zeichenkodierung: Unicode (UTF8) -> Linux Datei -> sed kommt da wohl nicht zurecht. Ich hab mir da jetzt was mit iconv zurecht gefummelt. Übrigens kam ich irgendwie nicht zurecht mit dem CR aus der Windows Datei, die musste ich auch erst mal eliminieren. Meine momentane funktionierende Lösung ist also: cat ersetzungen.txt | tr -d '\r' > ersetzungen_cr.txt iconv --from-code=ISO-8859-15 --to-code=UTF-8 ersetzungen_cr.txt > ersetzungen_neu.txt sed 's|\(.*\);\(.*\);\(.*\)|s/\3/\[*** \1 = \2 ***] \3/g|' ersetzungen_neu.txt | sed -f - quelldatei.txt > zieldatei.txt ... und die ersetzungen.txt muss vollständig sein, das heisst: alle 3 Spalten müssen befüllt sein
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.