Forum: PC-Programmierung Text-Ersetzungs-Einzeiler gesucht


von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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
von jobi (Gast)


Lesenswert?

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

von jobi (Gast)


Lesenswert?

Oh, habe die zweiter Anforderung überlesen...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von jobi (Gast)


Lesenswert?

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

von Yalu X. (yalu) (Moderator)


Lesenswert?

1
sed 's|"\(.*\)","\(.*\)"|s/\1/\[*** \2 ***] \1/g|' ersetzungen.txt | sed -f - logdatei.txt > logdatei_neu.txt

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> sed ...

Super Lösung +1

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Yalu, du bist mein Held! danke!

von Günter R. (guenter-dl7la) Benutzerseite


Lesenswert?

nebenbei betreffend Einzeiler: eine geniale Quelle ist auch
https://www.commandlinefu.com/commands/browse

von Bernd K. (prof7bit)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Hans (Gast)


Lesenswert?

Möchtest du mit deinen Ersetzungen etwa Wegstaben verbuchseln?

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Kommandozeile vor dem Frühstück für Alle! (Gast)


Lesenswert?

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

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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

von Bernd K. (prof7bit)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von A. S. (Gast)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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
von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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: `"'

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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ö

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
von A. S. (Gast)


Lesenswert?

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".

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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!

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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
Noch kein Account? Hier anmelden.