sed: langen Textblock ersetzen [gelöst]

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Karamel
Beiträge: 171
Registriert: 11.12.2006 20:48:12

sed: langen Textblock ersetzen [gelöst]

Beitrag von Karamel » 08.02.2021 11:21:54

In einem Script möchte ich einen Textblock ersetzen:
sed 's|alterText|neuerText|g'

Wie lang darf alterText sein, bzw. wie sähe das aus, wenn alterText eine eigene Datei ist? Das was da raus soll ist Javascript-Code, der z.B.Klammern, Semikolon, </script> enthält. Wird sed durch die Sonderzeichen gestört?
Zuletzt geändert von Karamel am 23.02.2021 20:21:14, insgesamt 1-mal geändert.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 08.02.2021 11:28:17

Sed arbeitet zeilenweise, der zu ersetzende Text kann also nur Teil einer Zeile sein. Mehrzeiliger Text kann mit sed so nicht ersetzt werden. (In Perl/Python/PHP/etc. ist das moeglich.)

Wenn der zu ersetzende Text ganze Zeilen umfasst, dann kann man das c-Kommando verwenden (oder `d' in Kombination mit `r'). Das ist aber alles nicht so bequem.

Kannst du dein Problem genauer beschreiben? Vielleicht auch ein Beispiel posten. Vielleicht gibt es ja auch andere Wege.
Use ed once in a while!

Karamel
Beiträge: 171
Registriert: 11.12.2006 20:48:12

Re: sed: langen Textblock ersetzen

Beitrag von Karamel » 08.02.2021 19:57:52

Es geht darum, eine Homepage zu reparieren. Da ist bei einem Angriff in sehr viele .php und .js-Dateien derselbe Javascript-(Schad-)Code eingefügt worden - allerdings an unterschiedlichen Stellen in der Datei: mal am Anfang, mal mittendrin. Ich habe vor Jahren mal für einen ähnlichen Zweck sed s benutzt, daher die Idee hier wieder sed zu benutzen.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 08.02.2021 20:05:01

Muss man den Codeblock loeschen oder ersetzen?

Hat der Textblock denn eine eindeutige Anfangs- und Endzeile? Wenn es die beiden genau einmal in den Dateien gibt und man den Block nur entfernen will, dann kann man das mit sed machen:

Code: Alles auswählen

sed -i '/eindeutiger-text-der-startzeile/,/eindeutiger-text-der-endzeile/d' DATEIEN...
(Davor ein Backup anlegen!)


Was bei sed nicht moeglich ist, ist ein Regulaerer Ausdrueck ueber mehrere Zeilen. Aber ein Perl-Programmierer kann dir sicher schnell einen Dreizeiler hinschreiben, der das kann.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 08.02.2021 20:23:46

Ich hab gerade mal 2 Minuten online gesucht (nach ``replace multiline string in text file'') und allerlei Antworten gefunden, u.a. diese: https://unix.stackexchange.com/question ... g-in-files

Die Essenz ist:

Code: Alles auswählen

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
Use ed once in a while!

uname
Beiträge: 12407
Registriert: 03.06.2008 09:33:02

Re: sed: langen Textblock ersetzen

Beitrag von uname » 09.02.2021 13:40:32

Meillo hat geschrieben:

Code: Alles auswählen

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
Zu "cat" fällt mir Useless use of * ein: https://www.socallinuxexpo.org/scale5x/ ... aumann.pdf (ab Seite 20)

Ich denke man könnte das auch ganz einfach mit "awk" schreiben.

- wenn Start gefunden setze einer Variable
- solange Variable gesetzt Zeile löschen
- wenn Stop gefunden die Variable nicht mehr setzen.

Vielleicht mag es jemand programmieren.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 09.02.2021 15:24:20

uname hat geschrieben: ↑ zum Beitrag ↑
09.02.2021 13:40:32
Meillo hat geschrieben:

Code: Alles auswählen

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
Zu "cat" fällt mir Useless use of * ein: https://www.socallinuxexpo.org/scale5x/ ... aumann.pdf (ab Seite 20)
Dazu habe ich auch etwas zu bieten: http://marmaro.de/docs/chaosseminar/on- ... rmance.pdf (ab Seite 5) ;-)

Ich denke aber, dass es sich hier um einen useful use of cat handelt, oder wie wuerdest du das sonst einfacher machen? Gibt es in Perl ein ``read file and return contents'' als Funktion?
Ich denke man könnte das auch ganz einfach mit "awk" schreiben.

- wenn Start gefunden setze einer Variable
- solange Variable gesetzt Zeile löschen
- wenn Stop gefunden die Variable nicht mehr setzen.

Vielleicht mag es jemand programmieren.
Nur wenn es eindeutige Start- und Endzeilen gibt. Dann geht es auch mit sed. Bislang war die Anforderung jedoch, dass es ein *mehrzeiliger* Suchstring ist ... und das kann weder sed noch awk direkt. Dazu muesste man sich selber etwas bauen. Perl aber kann das (mittels des `s' Parameters nach dem s///).
Use ed once in a while!

eggy
Beiträge: 3334
Registriert: 10.05.2008 11:23:50

Re: sed: langen Textblock ersetzen

Beitrag von eggy » 09.02.2021 19:09:42

Meillo hat geschrieben: ↑ zum Beitrag ↑
09.02.2021 15:24:20
Nur wenn es eindeutige Start- und Endzeilen gibt. Dann geht es auch mit sed. Bislang war die Anforderung jedoch, dass es ein *mehrzeiliger* Suchstring ist ... und das kann weder sed noch awk direkt. Dazu muesste man sich selber etwas bauen. Perl aber kann das (mittels des `s' Parameters nach dem s///).

Code: Alles auswählen

awk '{print NR " " NF}' datei.txt
vs

Code: Alles auswählen

awk 'BEGIN {RS = EOF}{print NR " " NF}' datei.txt
Als RS kann man auch nen regex benutzen. Mit anderen Worten, man könnte direkt an "<script" trennen bzw an "<script>" und "</script>" oder diversen Varianten davon.
Und da kommen wir zu dem Punkt, an dem man sich überlegen sollte, ob das ne gute Idee ist.
@Karamel : wenn Du das machst, sei Dir im klaren, dass Du vermutlich an einigen Stellen falsches löscht oder noch weitere Überreste der Scripte hinterblieben sind. Es ist sehr unwahrscheinlich, dass alle Modifikationen so einfach zu erkennen sind.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 09.02.2021 20:04:34

eggy hat geschrieben: ↑ zum Beitrag ↑
09.02.2021 19:09:42
Meillo hat geschrieben: ↑ zum Beitrag ↑
09.02.2021 15:24:20
Nur wenn es eindeutige Start- und Endzeilen gibt. Dann geht es auch mit sed. Bislang war die Anforderung jedoch, dass es ein *mehrzeiliger* Suchstring ist ... und das kann weder sed noch awk direkt. Dazu muesste man sich selber etwas bauen. Perl aber kann das (mittels des `s' Parameters nach dem s///).

Code: Alles auswählen

awk '{print NR " " NF}' datei.txt
vs

Code: Alles auswählen

awk 'BEGIN {RS = EOF}{print NR " " NF}' datei.txt
Richtig! :THX: Awk kann es. Da hatte ich einen Knoten im Hirn. ;-)
Als RS kann man auch nen regex benutzen. Mit anderen Worten, man könnte direkt an "<script" trennen bzw an "<script>" und "</script>" oder diversen Varianten davon.
Und da kommen wir zu dem Punkt, an dem man sich überlegen sollte, ob das ne gute Idee ist.
@Karamel : wenn Du das machst, sei Dir im klaren, dass Du vermutlich an einigen Stellen falsches löscht oder noch weitere Überreste der Scripte hinterblieben sind. Es ist sehr unwahrscheinlich, dass alle Modifikationen so einfach zu erkennen sind.
Wenn er nicht nur auf irgendwelche *vermutlich* nur einmal vorkommende Marker matcht, sondern den spezifischen Textblock insgesamt ersetzt (wie das mit dem Perl-Befehl moeglich ist), dann ist das deutlich robuster. Es ist dann zwar auch kein String-Search-Replace, sondern ein RE-Matchen-Replace, aber immerhin.

In den modernen Scriptsprachen sollte das alles kein grosses Problem sein.

... wobei es in diesem Thread ja gerade weniger an den Moeglichkeiten scheitert, als mehr daran, dass Karamel sich nicht mehr meldet. ;-)
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 09.02.2021 20:56:10

In PHP (weil Perl oder Python kann ich nicht) koennte das in etwa so aussehen:

Code: Alles auswählen

$file = "foo.html";
$data = file_get_contents($file);

$search = <<<'EOF'
<script>
... beliebige Zeilen ...
</script>
EOF;

$replace = <<<'EOF'
leer oder Ersatzzeilen
EOF;

file_put_contents($file, str_replace($search, $replace, $data));
(Ungetesteter Code!)

Letztlich fehlt nur der Input fuer die Liste von Dateien, in denen ersetzt werden soll, ueber die iteriert werden muss ... und alle Fehlerbehandlung. ;-) Vom Prinzip waere das ein reiner String-Replace, in dem nichts escapt werden muss oder so.

Btw: Man muss das Paket Debianphp7-cli installieren, um PHP fuer Scripte von der Kommandozeile nutzen zu koennen.
Use ed once in a while!

Karamel
Beiträge: 171
Registriert: 11.12.2006 20:48:12

Re: sed: langen Textblock ersetzen

Beitrag von Karamel » 14.02.2021 10:59:37

Meillo hat geschrieben: ↑ zum Beitrag ↑
08.02.2021 20:05:01
Muss man den Codeblock loeschen oder ersetzen?

Hat der Textblock denn eine eindeutige Anfangs- und Endzeile? Wenn es die beiden genau einmal in den Dateien gibt und man den Block nur entfernen will, dann kann man das mit sed machen:

Code: Alles auswählen

sed -i '/eindeutiger-text-der-startzeile/,/eindeutiger-text-der-endzeile/d' DATEIEN...
Danke Mello, soweit ich das verstanden habe, werden dann die ganzen Zeilen gelöscht. Allerdings bin ich mir nicht sicher, ob der Schadcode immer am Zeilenanfang anfängt und am Zeilenende endet. Deshalb bin ich zu Plan B übergegangen, d.h. ich versuche den Schadcode scheibchenweise abzutragen. Das funktioniert auch bei den ersten Scheiben, aber hier funktioniert es nicht:

Code: Alles auswählen

ft4="(String.fromCharCode(115,99,114,105,112,116))[0]);elem.appendAfter(document.getElementsByTagName(String.fromCharCode(104,101,97,100))[0]);"
ft5="document.getElementsByTagName(String.fromCharCode(104,101,97,100))[0].appendChild(elem);})();"

sed "s|$ft4||g" test.php > test.php.tmp && mv test.php.tmp test.php
sed "s|$ft5||g" test.php > test.php.tmp && mv test.php.tmp test.php

Karamel
Beiträge: 171
Registriert: 11.12.2006 20:48:12

Re: sed: langen Textblock ersetzen

Beitrag von Karamel » 16.02.2021 22:21:17

Ich habe den Befehl nochmal einfach auf der Kommandozeile eingegeben, aber obwohl ich den Suchtext aus der Test-Datei rauskopiert habe, findet keine Ersetzung (bzw. Löschung) statt.

Benutzeravatar
detix
Beiträge: 1743
Registriert: 07.02.2007 18:51:28
Wohnort: MK

Re: sed: langen Textblock ersetzen

Beitrag von detix » 17.02.2021 12:24:09

sed stört sich wohl an den vielen Klammern_auf...
vielleicht gehts mit einem kleinen Umweg (Ersetzung durch Punkt):

Code: Alles auswählen

ft41=$(echo ${ft4//[([{]/.})
ft51=$(echo ${ft5//[([{]/.})

sed "s|$ft41||g" test.php > test.php.tmp && mv test.php.tmp test.php
sed "s|$ft51||g" test.php > test.php.tmp && mv test.php.tmp test.php
Gruß an alle Debianer, und immer daran denken:
Macht ohne Haftung funktioniert nicht!

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 17.02.2021 12:34:50

Mein Eindruck ist, dass dieser ganze Ansatz mit sed mehr Hindernis als Hilfe ist. Nichts Schlimmeres wie wenn man irgendwann halb oder teilweise ersetzte Daten hat. Mit sed gibt es so viele Stolpersteine, die es zu nehmen gilt.

Ich moechte doch nochmal empfehlen ein Script in Perl/PHP/Python/Ruby/etc. zu verwenden, das in einer Datei (unabhaengig von Zeilen) Textbloecke ersetzen kann. Beispiele fuer solche Umsetzungen habe ich fuer Perl und fuer PHP gepostet. Dann in der Shell ueber alle Dateien iterieren und fuer jede das Script aufrufen. Anschliessend stichprobenhaft pruefen, dass aller unerwuenschter Code ersetzt worden ist.

Selbst wenn du diese Programmiersprachen nicht kannst, denke ich, dass dich dieser Ansatz schneller und v.a. robuster zum Ziel bringt als mit sed rumzuwerkeln. (Wir koennen dich bei deinen Versuchen ja unterstuetzen.) Aber naterlich kannst du es machen wie du es willst, und es gibt hier vielleicht auch andere Meinungen als meine ...
Use ed once in a while!

Karamel
Beiträge: 171
Registriert: 11.12.2006 20:48:12

Re: sed: langen Textblock ersetzen

Beitrag von Karamel » 18.02.2021 20:13:14

Mello, vielen Dank für das Hilfsangebot, aber ich möchte erst einmal versuchen, das Problem mit den Mitteln zu lösen, die ich halbwegs verstehe, bzw. mit den Mitteln, die ich kurzfristig in der Lage bin dazuzulernen.

detix, das sieht interessant aus, aber ich verstehe nur, dass die Variable ft4 ausgegeben wird, mit der Ausgabe offenbar etwas angestellt wird und das Ergebnis in Variabl2 ft41 gespeichert wird. Was passiert da genau?

Benutzeravatar
detix
Beiträge: 1743
Registriert: 07.02.2007 18:51:28
Wohnort: MK

Re: sed: langen Textblock ersetzen

Beitrag von detix » 19.02.2021 10:43:07

Führe es doch einfach aus:

Code: Alles auswählen

echo $ft5
document.getElementsByTagName(String.fromCharCode(104,101,97,100))[0].appendChild(elem);})();
echo ${ft5//[([{]/.}
document.getElementsByTagName.String.fromCharCode.104,101,97,100)).0].appendChild.elem);}).);
es werden sämtliche öffnende runde, eckige und geschweifte Klammern durch einen Punkt ersetzt, letzterer steht für jedes x-beliebige Zeichen, so kann sed auch den kompletten String finden und ersetzen.

Allerdings wird das so nichts werden, zumindest für $ft5 fehlen dir zugehörige öffnende Klammern und doppelte Anführungszeichen, das zerreißt dir alles!
So einfach wie du denkst wird der Schaden nicht zu reparieren sein.
Gruß an alle Debianer, und immer daran denken:
Macht ohne Haftung funktioniert nicht!

Karamel
Beiträge: 171
Registriert: 11.12.2006 20:48:12

Re: sed: langen Textblock ersetzen

Beitrag von Karamel » 22.02.2021 20:24:58

So, ich hab's hinbekommen. Gestolpert ist sed über die eckigen Klammern. DIe habe ich aber mit Mellos Zeile mit -i und d auch noch weggetrickst.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: sed: langen Textblock ersetzen

Beitrag von Meillo » 22.02.2021 20:42:37

Karamel hat geschrieben: ↑ zum Beitrag ↑
22.02.2021 20:24:58
So, ich hab's hinbekommen. Gestolpert ist sed über die eckigen Klammern. DIe habe ich aber mit Mellos Zeile mit -i und d auch noch weggetrickst.
Cool. :-)

Hast du das Problem damit geloest? Ist aller Stoertext entfernt? (Falls ja, dann ergaenze den Titel im ersten Post doch um ein [gelöst].)


Btw: Meillo. ;-)
Use ed once in a while!

Antworten