Sed ersetzen von Variablen in einem speziellen Muster

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 12.05.2023 15:30:54

Ich arbeite an einem etwas außergewöhnlichen Script, was innerhalb einer Datenbank mir Sätze vorschlägt, die ich vervollständigen kann. Das Programm funktioniert ganz gut und teilt mir auch Vorschläge mit, wie ich mein Satz vervollständigen kann. Ich arbeite nun an dem Feinschliff und habe das Problem, dass ich in diesem Punkt nicht weiterkomme. Das Programm besitzt eine Keyloger Funktion und schreibt die jeweiligen Tastenanschläge in ein File ab. Das File sieht in etwa so aus:

Code: Alles auswählen

${A57}${A17}${A23}${A20}${A35}${A57}${A33}${A24}${A38}${A38}${A24}${A17}${A57}${A33}${A23}${A38}${A18}${E52}${A28}${A28}${A28}${A25}${A38}${A22}${A50}${A30}${A57}${A37}${A18}${A44}${A15}${A28}${A29}${A29}${A29}${A29}${A14}
Ich möchte nun gerne wenn ich die Taste Strg+Backspace betätige, dass alles bis zum Whitespace gelöscht wird. Dazu könnte man theoretisch sed oder grep nutzen, der Befehl mit Output würde dazu lauten:

Code: Alles auswählen

grep -o "${A57}.\*${A29}${A14}" keymap.log
${A57}${A17}${A23}${A20}${A35}${A57}${A33}${A24}${A38}${A38}${A24}${A17}${A57}${A33}${A23}${A38}${A18}${E52}${A28}${A28}${A28}${A25}${A38}${A22}${A50}${A30}${A57}${A37}${A18}${A44}${A15}${A28}${A29}${A29}${A29}${A29}${A14}

Hierbei stehen die Variablen für:

Code: Alles auswählen

A57=Whitespace 
A29=Strg 
A14=Backspace
Das Problem ist nun, dass ich ein Befehl benötige der bis zum nächstgelegenen Whitespace geht und die Zeichenabfolge bis da löscht. Der gewünschte Wert der gelöscht werden sollte wäre dann:
${A57}${A37}${A18}${A44}${A15}${A28}${A29}${A29}${A29}${A29}${A14}

Nun meine Frage: Wie kann ich sed dazu bringen, dass er beim ersten Match von ${A57} aufhört?

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 12.05.2023 17:37:09

Es hat ein bisschen gedauert, bis ich begriffen habe, dass du die Datei von hinten betrachtest. Normalerweise beschreibt man sowas von vorne.

Folgendes löscht mit GNU-Sed vom letzten "${A57}" bis zum danach folgenden letzten "${A29}${A14}" (was auch das erste und einzige "${A29}${A14}" nach dem letzten "${A57}" ist?):

Code: Alles auswählen

sed 's/\${A57}/\x1/g;s/\x1[^\x1]*\${A29}\${A14}//;s/\x1/${A57}/g'
Falls das letzte "${A29}${A14}" identisch mit dem Dateiende ist, dann kann man das noch abkürzen:

Code: Alles auswählen

sed 's/\${A57}/\x1/g;s/\x1[^\x1]*$//;s/\x1/${A57}/g'
Alternativ könnte man die Datei auch mit tac rumdrehen, bis zum ersten "${A57}" löschen und dann wieder rumdrehen.

DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 13.05.2023 04:04:25

Das ist schon mal ein richtiger Ansatz, jedoch sind mehrere Bedingungen gegeben, die es etwas verkomplizieren.

Das Problem an :

Code: Alles auswählen

sed 's/\${A57}/\x1/g;s/\x1[^\x1]*\${A29}\${A14}//;s/\x1/${A57}/g'
Der Befehl löscht am Anfang vom File den Wert: "${A57}.\*${A29}${A14}" und wie ich es ausprobiert habe, überspringt er einmal "${A29}${A14}". Hierbei ein Beispiel für ein besseres Verständnis:

EDIT :: ohne sed
EDIT :: mit sed

In den Bildern lässt sich entnehmen das der Befehl diese Zeichenabfolge am Anfang löscht: "${A57}${A14}${A29}${A14}${A28}${A29}${A29}${A29}${A29}${A14}"

Ich möchte nun, dass der Befehl die Zeichenabfolge nicht am Anfang sondern am Ende vom File löscht und die Kondition: Das einmal "${A57}" und "{A29}${A14}" vorkommt und alles dazwischen gelöscht wird, also: "${A57}${A14}${A29}${A14}". Es würde auch gehen wenn alle vorhandenen Zeichenabfolgen von: "${A57}.\*${A29}${A14}" in der Datei gelöscht wird, wäre glaub ich sogar besser.
Zuletzt geändert von DeadGame am 16.05.2023 15:36:59, insgesamt 1-mal geändert.

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 13.05.2023 09:19:23

DeadGame hat geschrieben: Es würde auch gehen wenn alle vorhandenen Zeichenabfolgen von: "${A57}.\*${A29}${A14}" in der Datei gelöscht wird, wäre glaub ich sogar besser.
Mit
x=${A57}
y=${A29}${A14}
wird jetzt jedes x[^xy]*y gelöscht:

Code: Alles auswählen

sed 's/\${A57}/\x1/g;s/\${A29}\${A14}/\x3/g;s/\x1[^\x1\x3]*\x3//g;s/\x1/${A57}/g;s/\x3/${A29}${A14}/g
Wenn das nicht das ist, was du willst, dann Eingabe(n) und erwartete Ausgabe(n) in Textform zeigen (keine Prosa, keine Bilder), damit man das direkt am Beispiel nachvollziehen kann.

DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 13.05.2023 14:28:47

Der Befehl passt wunderbar :THX: Ebenfalls konnte ich daraus auch etwas mitnehmen und lernen. Das einzige Problem was noch bestehen würde wäre, dass wenn man mehrmals Strg+Backslash betätigt es ab der zweiten getrennten Zeichenkette – getrennt durch Whitespace – Stuckt. Ich hab mir noch nicht so richtig Gedanken darüber gemacht und müsste das Problem erstmal evaluieren. Ich würde sagen, dass der Thread noch offen bleiben sollte, damit ich, wenn ich nicht weiter komme mich ein weiteres mal an euch wenden könnte.

DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 16.05.2023 15:22:56

Ich hab ein paar Änderungen ausgeführt, die es mir etwas übersichtlicher machen. Aus ${A29}${A14} – Strg + Backspace – wird nun ${E14}.

Den sed Interpreter habe ich noch nicht so richtig Verstanden, ganz besonders die definierte Zeichenklasse "[^\x1\x3]*". Theoretisch könnte man das auch anders Formulieren? Bsp.: [^\${A57}^\${E14}]* , da ja am Anfang \x1 und \x3 durch diese Werte ersetzt werden. Naja am liebsten würde ich mir den Regex Statment selber zusammenbasteln, aber ich stehe da etwas Kopflos da. Bevor ich nun weitere Stunden damit verbringe meine Lösung durch probieren und Google rauszufinden, ist es womöglich am besten nochmals nachzufragen. Mir sind zwei Probleme aufgefallen, die womöglich meine Fragestellung endgültig löst.

Problem 1:

Zwischen den Werten ${A57} und ${E14} muss die Bedingung gesetzt werden, dass ein Inhalt sich darin befinden. Der Grund ist, wenn bei einem Wort ein Whitespace sich davor befindet wie zbsp.:

Code: Alles auswählen

"${A17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}"
"wir haben "
Dann hat der Befehl wenig Auswirkung auf das löschen vom Wort "haben ", denn er löscht nur das davor gesetzte Whitespace.

Problem 2:

Die Mehrfache ausführung von "Strg + Backspace" funktioniert nur einmalig, dass heißt, bei einem Satz wie zbsp:

Code: Alles auswählen

"${A17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}"
"wir haben"
Lässt sich mit der ersten ausführung von ${E14} das Wort haben löschen. Bei der zweiten ausführung Stuckt es jedoch und das Wort "wir" bleibt erhalten.

Es ist mir nicht möglich, das File mit dem Input zu verändern, da die Tastenanschläge durch ein C Programm in das File geschrieben wird. Das Problem ist nun, wenn ich mit sed das File bearbeiten würde, bricht der Stream mit dem C Programm ab und kann keinen weiteren Input in das File schreiben. Das File wird in einem Bashscript in eine Variable geladen und mit eval infolge aufgelöst.

Code: Alles auswählen

echo -e ":$(eval echo "$(cat $file | sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g;s/[^\x1\x3]*\x3//g;s/\x1/${A57}/g;s/\x3/${E14}/g')" | sed 's/\\n/˽/g')" | sed ':s; s#[^\x08]\x08##g; t s' | sed 's/˽/\\n/g' | sed 's/[.]/\\n/g')
Ich würde es mir wünschen und es würde mir sehr helfen, wenn ich am besten mit einem Einzeiler die genannten Probleme dadurch lösen könnte und bin auch sehr Wissbegierig darüber, wie ich zukünftig selber einen Regex Statment aufbauen kann, der mir künftig in einem Ähnlichen Problem helfen könnte.

Hier ist kleine Vorschau darüber, was genau das Programm bezwecken sollte:

https://ibb.co/SxMQZT3

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 16.05.2023 16:35:36

Du hast also nach E14 verändert/erweitert - wie soll ich irgendwas deiner Prosa verstehen, wenn in deinen Beispielen überhaupt kein E14 vorkommt? Es gilt mein letzter Satz aus dem Beitrag darüber!

Zusätzlich noch 2 Sachen: Ist der Zeilenumbruch da nur angedeutet oder vorhanden und willst du dieses Sed-Skript bei jedem Tastenanschlag aufrufen?

DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 16.05.2023 16:57:21

Im Beispiele kannst du E14 gerne am Ende hinzufügen. Wie ich es im ersten Problem geschildert habe, muss sich zwischen den zwei Variablen als Bedingungen ein Inhalt befinden, da er ansonsten nur den Whitespace am Ende des Wortes löscht und nicht das ganze Wort.

Der Zeilenumbruch ist vorhanden, es wird jedoch im Terminal nur der Inhalt der letzten Zeile ausgegeben – siehe Bild.

Das Script läuft in einer Endlosschleife und aktualisiert die Ausgabe bei jedem Tastenanschlag .

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 16.05.2023 17:24:19

Zeilenübergreifend, dann starte sed mit Parameter -x. Ansonsten brauchts Textbeispiele für Eingaben und dazugehörige erwartete Ausgaben.

chrbr
Beiträge: 547
Registriert: 29.10.2022 15:53:26

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von chrbr » 16.05.2023 18:04:00

DeadGame hat geschrieben: ↑ zum Beitrag ↑
16.05.2023 15:22:56
Den sed Interpreter habe ich noch nicht so richtig Verstanden, ganz besonders die definierte Zeichenklasse "[^\x1\x3]*"
Ich habe da auch eine ganze Zeit daran herum gekaut und gemeint, dass wären sed Features oder spezielle Variable, die ich nicht kenne. Pustekuchen, es ist viel einfacher. Ich greife einfach mal etwas heraus.
DeadGame hat geschrieben: ↑ zum Beitrag ↑
13.05.2023 04:04:25
sed 's/\${A57}/\x1/g;s/\x1[^\x1]*\${A29}\${A14}//;s/\x1/${A57}/g'
Das sind eigentlich drei suchen&ersetzen Befehle. Das \x1 ist dabei quasi ein Byte mit dem Wert 0x01 und nicht darstellbar. Interessant wird es, wenn man das \x1 durch ein druckbares Zeichen ersetzt. Nun nimm eines deiner Testfiles und pipe das durch

Code: Alles auswählen

sed 's/\${A57}/#/g
.
Es werden also alle $A57 durch Doppelkreuze # ersetzt. Im nächsten Schritt

Code: Alles auswählen

sed 's/#[^#]*\${A29}\${A14}//'
wird die Folge von "Doppelkreuz", "Beliebig viele Nicht-Doppelkreuz", "${A29}" und "${A14}" gelöscht.
Im letzten Schritt
sed 's/#/${A57}/g'
werden die Änderungen aus dem 1. Schritt wieder rückgängig gemacht. Alle verbliebenen Doppelkreuze werden wieder durch ${A57} ersetzt.

Warum der Zauber? Intuitiv würde man den Teil im zweiten Schritt
sed 's/#[^#]*...
anders beschreiben wollen. [^#]* sind ja beliebig viele nicht Doppelkreuze. Also warum nicht den Teil durch etwas wie
sed 's/${A57}[^${A57}]*...
ersetzen? Bei regulären Ausdrücken kann man aber keine Zeichenfolgen negieren. Deshalb muss der Umweg über ein Zeichen erfolgen, der in den Eingangsdaten nicht vorkommt. So kann man die Zeichenfolge ${A57} durch dieses spezielle Zeichen ersetzten, die gewünschten Operationen durchführen und zum Schluss die verbliebenen Spezialzeichen wieder durch ${A57} ersetzten.

Nochmal von oben:
DeadGame hat geschrieben: ↑ zum Beitrag ↑
16.05.2023 15:22:56
Den sed Interpreter habe ich noch nicht so richtig Verstanden, ganz besonders die definierte Zeichenklasse "[^\x1\x3]*"
"[^\x1\x3]*" sind beliebig viele Zeichen, die weder 0x01 noch 0x03 sind. Das "Match" in dem regulären Ausdruck passt, so lange keines der beiden Zeichen gefunden wird.

Wenn Du die sed Befehle mit druckbaren Zeichen der Reihe nach an deinen Beispielen nachvollziehst wird dir das alles ebenfalls klar.

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 16.05.2023 18:16:08

Man kann sich das relativ schnell erschließen, wenn man da mit od draufschaut:

Code: Alles auswählen

$ echo "_X_" | sed 's/X/\x1/' | od -c
0000000   _ 001   _  \n
0000004
$

chrbr
Beiträge: 547
Registriert: 29.10.2022 15:53:26

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von chrbr » 16.05.2023 19:53:51

Hallo Tobo,
klar, nur hätte ich allein aus Schreibfaulheit das # verwendet anstatt des \x1. Das \x1 tritt allerdings mit verschwindender Wahrscheinlichkeit in der Testdatei und späteren Eingangsdaten auf. Deshalb ist das schon besser, sieht aber extrem Guru-mäßig aus, jedenfalls wenn es im Rudel auftritt :mrgreen: . Darum habe ich erst auf mir unbekannte sed Features getippt. Und wenn man sich erst einmal in etwas verrannt hat, dann kommt man ja nicht so schnell zurück auf die richtige Spur. Zumindest mir geht das oft so.
Viele Grüße,
Christoph

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 16.05.2023 20:15:32

Die Idee mit dem nicht darstellbaren Zeichen ist ziemlich praktisch - habe ich hier von Meillo.

DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 16.05.2023 20:34:43

tobo hat geschrieben: ↑ zum Beitrag ↑
16.05.2023 17:24:19
Zeilenübergreifend, dann starte sed mit Parameter -x. Ansonsten brauchts Textbeispiele für Eingaben und dazugehörige erwartete Ausgaben.
Ich hab mich da etwas falsch ausgedrückt. Die Variablen werden ohne Zeilenumbruch im Textfile dargestellt Bsp.:

Code: Alles auswählen

${A105}${A105}${A105}${A105}${A28}${E46}${E47}${E33}${B31}${A46}${A19}${E47}${A28}
Hierbei ist der Wert ${A28} der Zeilenumbruch. Erst bei der Variablen auflösung wird alles im Klartext angezeigt mit Zeilenumbruch.

Kommen wir zu dem Beispielen:
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}
"Wir haben heute gut gegessen "
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}
Wenn wir nun auf den Einzeiler den Sed Befehl wirken, erhalten wir:

Code: Alles auswählen

echo '${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}' | sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g;s/[^\x1\x3]*\x3//g;s/\x1/${A57}/g;s/\x3/${E14}/g'
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}
"Wir haben heute gut gegessen "
Ich möchte aber folgenden Output:
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}
"Wir haben heute gut "
Und Optional wenn es Möglich wäre, wenn mehrmals ${E14} ausgelöst wird:
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}${E14}${E14}
"Wir haben heute gut gegessen "
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}
"Wir haben "
@chrbr Anfangs habe ich Verstanden, dass es sich hierbei um nicht dargestellte Zeichen (\x1\x3) handelt, fand ich auch cool, dass man mit diesem kleinen Trick etwas versteckt ändern, und dann wieder zurücksetzen kann. Eigentlich könnte man anstelle \x1\x3 auch einzigartige Symbole anwenden die man im Nachhinein wieder zurücksetzt, wie in deinem Beispiel: #. Jedoch ist die Ausführung in diesem Bereich von tobo etwas eleganter. Was ich mich aber immernoch Frage ist die Zeichenklasse: [^\x1\x3]*, denn ^ steht für den Zeilenanfang; \x1=${A57} und \x3=${E14} für die davor versteckten Werte. Nun Frage ich mich zwei Sachen: Das File hat kein Zeilenumbruch und wie es aussieht ersetzt er die Werte am Ende vom Einzeiler, müsste er nicht am Anfang die Werte ersetzen? Was ich mich auch noch Frage ist, zwischen "\x1\x3" ist kein ".*", in meine Betrachtung würde das heißen, dass der Werte "${A57}${E14}" ausschließlich ersetzt wird. Entweder habe ich ein Denkfehler oder es handelt sich bei der Zeichenklasse um etwas, was ich noch nicht richtig begriffen habe. Müsste selber mal eine Zeitlang damit rumprobieren – Regex ist schon was schönes :P .
Zuletzt geändert von DeadGame am 16.05.2023 22:53:09, insgesamt 1-mal geändert.

chrbr
Beiträge: 547
Registriert: 29.10.2022 15:53:26

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von chrbr » 16.05.2023 22:00:06

Hallo @DeadGame, hallo @tobo,
vielen Dank für den Link. Meillo ist ohne Zweifel ein Guru.
Den oberen Teil des letzten Posts muss ich erst einmal nachvollziehen. Zum zweiten Teil antworte ich hier.
DeadGame hat geschrieben: ↑ zum Beitrag ↑
16.05.2023 20:34:43
@chrbr Anfangs habe ich Verstanden, dass es sich hierbei um nicht dargestellte Zeichen (\x1\x3) handelt, fand ich auch cool, dass man mit diesem kleinen Trick etwas versteckt ändern, und dann wieder zurücksetzen kann. Eigentlich könnte man anstelle \x1\x3 auch einzigartige Symbole anwenden die man im Nachhinein wieder zurücksetzt, wie in deinem Beispiel: #. Jedoch ist die Ausführung in diesem Bereich von tobo etwas eleganter.
Na klar, meine Version ist nur zur Visualisierung.
DeadGame hat geschrieben: ↑ zum Beitrag ↑
16.05.2023 20:34:43
Was ich mich aber immernoch Frage ist die Zeichenklasse: [^\x1\x3]*, denn ^ steht für den Zeilenanfang; \x1=${A57} und \x3=${E14} für die davor versteckten Werte.
Hier hat das ^ nicht wie sonst die Bedeutung vom Zeilenanfang. Als erstes Zeichen in der Definition der Zeichenklasse bedeutet es dessen Negation. Zum Beispiel würde [rot] auf alle Zeichenfolgen passen, die diese Buchstaben enthalten. Das wären rot, tor, or und nur einer der Buchstaben wie t. Die Negation [^rot] passt dann auf alle Zeichen oder Zeichenfolgen, in denen weder ein r, ein o oder ein t vorkommen. Beispiele wären "12uvw", "--##" und so weiter. Nicht passen würden "12rvw", "auto" und so weiter.

Besser als meine amateurhafte Schreiberei ist allerdings diese Referenz: https://wiki.debianforum.de/Regul%C3%A4 ... r%C3%BCcke
Der Kurs von Meillo etwas unten im Link ist absolut empfehlenswert.

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 17.05.2023 00:34:13

Folgendes sed-Skript erfüllt deine beiden Anforderungen:

Code: Alles auswählen

sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g; :m s/\x1[^\x1\x3]*\x1\?\x3//; tm; /\x1$/!s/$/${A57}/; s/\x1/${A57}/g;s/\x3/${E14}/g'

Code: Alles auswählen

$ echo '${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}' | sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g;   :m s/\x1[^\x1\x3]*\x1\?\x3//; tm; /\x1$/!s/$/${A57}/;    s/\x1/${A57}/g;s/\x3/${E14}/g'
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}
$ 
$ echo '${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}${E14}${E14}' | sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g;   :m s/\x1[^\x1\x3]*\x1\?\x3//; tm; /\x1$/!s/$/${A57}/;    s/\x1/${A57}/g;s/\x3/${E14}/g'
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}
$ 
Zur Erklärung:

Code: Alles auswählen

:m s/\x1[^\x1\x3]*\x1\?\x3//; tm; 
Das ist eine Schleife, wobei :m dabei die Markierung m darstellt. Das t von tm ist ein bedingter Sprung, m ist die Marke wohin gesprungen werden soll. Will heißen, wenn der Programmlauf zu tm kommt, dann geht's bei Marke m weiter. Das allerdings nur, wenn davor eine Substitution erfolgt ist. deswegen bedingter Sprung.
Die Substitution sagt: ersetze ein \x1, dann beliebig viiele Zeichen, die nicht \x1 oder \x3 sind ([^\x1\x3]*), dann ein mögliches \x1 (\x1\?) und dann ein \x3 mit Nichts. Bedeutet also, lösche diesen gesamten Teil.

Code: Alles auswählen

/\x1$/!s/$/${A57}/;
Wenn am Zeilenende nach der Ersetzung kein {A57} steht, dann füge es hinzu. Das ist dem Umstand geschuldet, dass es jetzt zu spät zum Denken ist, denn es wird nicht ordnungsgemäß funktionieren, wenn es eine \x1\x1 Dublette am Ende geben würde; der Text also regulär mit \x1 aufhört. Grundsätzlich also dem Problem geschuldet, dass beim mehrmaligen Löschen von \x1\x3-Paaren nur beim letzten Paar eine Ersetzung zu \x1 stattfindet.
Wenn mit x=\x1 und y=\x3 ersetzt wird, dann löst sich der Text "axbxcxyyy" folgendermaßen auf (Edit: Beispiel korrigiert):
"axbxcxdxyyy" -xdxy (xy wegen \x1\?)
"axbxcyy" -xcy
"axby" -xby +x
"ax"
Da denke ich aber erst morgen nochmal drüber nach...

Edit:
Eine Verständnisfrage für mich hätte ich aber noch: Wie kann es sein, dass am Ende "...${A57}${E14}${E14}${E14}" 3x ${E14} auftaucht, wenn nach jeder Taste ausgewertet wird und "${A57}${E14"-Paae bearbeitet werden sollen?

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von tobo » 17.05.2023 08:57:51

Die Tageszeit ist manchmal echt ein Faktor. Wegen deiner zusätzlichen Einschränkung, dass \x1\x3 ignoriert werden soll, kann man grundsätzlich mit \x1 ersetzen:

Code: Alles auswählen

sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g; :m s/\x1[^\x1\x3]*\x1\?\x3/\x1/; tm; s/\x1/${A57}/g;s/\x3/${E14}/g'
Ich hoffe, dass das jetzt alles abdeckt.

Code: Alles auswählen

$ echo '${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}' | sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g; :m s/\x1[^\x1\x3]*\x1\?\x3/\x1/; tm; s/\x1/${A57}/g;s/\x3/${E14}/g'
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}
$ 
$ echo '${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}${A35}${A18}${A22}${A20}${A18}${A57}${A34}${A22}${A20}${A57}${A34}${A18}${A34}${A18}${A31}${A31}${A18}${A49}${A57}${E14}${E14}${E14}' | sed 's/\${A57}/\x1/g;s/\${E14}/\x3/g; :m s/\x1[^\x1\x3]*\x1\?\x3/\x1/; tm; s/\x1/${A57}/g;s/\x3/${E14}/g'
${B17}${A23}${A19}${A57}${A35}${A30}${A48}${A18}${A49}${A57}
$
Im Kleinen ist das bestimmt viel einfacher zu verstehen:

Code: Alles auswählen

$ echo axxbxcxdxy | sed ':m s/x[^xy]*x\?y/x/; tm;'
axxbxcx
$ echo axxbxcxdxyy | sed ':m s/x[^xy]*x\?y/x/; tm;'
axxbx
$ echo axxbxcxdxyyy | sed ':m s/x[^xy]*x\?y/x/; tm;'
axx
$ echo axxbxcxdxyyyy | sed ':m s/x[^xy]*x\?y/x/; tm;'
ax
$ echo axxbxcxdxyyyyyyyyyy | sed ':m s/x[^xy]*x\?y/x/; tm;'
ax
$

DeadGame
Beiträge: 20
Registriert: 17.11.2021 22:14:57

Re: Sed ersetzen von Variablen in einem speziellen Muster

Beitrag von DeadGame » 17.05.2023 17:28:32

@tobo du bist ein Magier. Dachte wirklich nicht das sich die zweite Option in einem Inliner integrieren lässt. Das mit der Schleife ist hoch interessant – kannte ich selbst nicht. Ich hab die Zeile im Script integriert und es scheint so zu funktionieren, wie ich es mir vorgestellt habe. Vielen Dank ! Nun ist die Frage ob sich Zukünftig weitere Faktoren bilden, die einer Fehlermeldung gleichen. Jedoch bin ich sehr optimistisch und denke das ich – notfallsweiße wir – das geschaukelt bekomme.

Zu deiner Verständnisfrage:: ${E14} – E steht für "Strg" und 14 für Backspace. Man könnte es auch anders Formulieren: ${E57}, dass wäre: Strg + Whitespace. Ich habe mich für diese Formatierung entschieden, da es übersichtlicher ist und das Potenzial hat, weitere Kombinationen (strg,alt,capslock etc..) als Buchstaben zu deklarieren. Capslock wäre zum Beispiel: ${B}

Ich mach mich jetzt erstmals bzgl den neu erfassten Statements vertraut. Ich werd das Script bei Fertigstellung auf Github puplizieren, jedoch dauert es noch etwas, bis alles so läuft wie es laufen soll.

Bis dahin bin ich fleißig am Werkeln :THX:

@chrbr Den Kurs von Meillo werd ich mir genauer anschauen. Danke für die Empfehlung und für die ausführliche Erklärung. Das mit der Negation durch ^ in einer Zeichenklasse ist sehr interessant, mit Grep kann man damit gut rumprobieren und so ein besseres Verständnis aufbauen.

Antworten