Ersetzen Sie mehrzeilige Zeichenfolgen in Dateien

17

Ich möchte eine Reihe von Dateien aktualisieren, indem ich eine mehrzeilige Zeichenfolge durch eine andere mehrzeilige Zeichenfolge ersetze. Etwas in der Art von:

* Some text, 
* something else
* another thing

Und ich möchte es ersetzen durch:

* This is completely
* different text

Das Ergebnis wäre, dass nach dem Ersetzen die Datei, die den ersten Textblock enthält, jetzt die zweite Zeichenfolge enthält (der Rest der Datei bleibt unverändert).

Ein Teil des Problems ist, dass ich die Liste der zu aktualisierenden Dateien im Dateisystem finden muss. Ich schätze, ich kann grep dafür verwenden (obwohl das wiederum mit mehrzeiligen Zeichenfolgen nicht so einfach ist), um es dann vielleicht in sed zu leiten?

Gibt es eine einfache Möglichkeit, dies zu tun? Sed ist eine Option, aber es ist umständlich, weil ich hinzufügen muss \ n usw. Gibt es eine Möglichkeit zu sagen, "die Eingabe aus dieser Datei zu übernehmen, sie in diesen Dateien abzugleichen und sie dann durch den Inhalt dieser anderen Datei zu ersetzen"? Ich kann bei Bedarf Python verwenden, aber ich möchte etwas schnelles und einfaches. Wenn also ein Dienstprogramm verfügbar ist, würde ich dieses lieber verwenden, als mein eigenes Skript zu schreiben (das ich zu schreiben weiß).

ventsyv
quelle
Sie sollten dafür wahrscheinlich Perl verwenden. stackoverflow.com/questions/1030787/…
orion
3
Sie möchten also some text, something else another thingfeststellen, ob es sich über mehrere Zeilen erstreckt oder nicht? Oder wollen Sie nur zusammenpassen some text,\nsomething else\nanotherthing?
mikeserv
2
Bearbeiten Sie Ihre Frage und klären Sie, was genau der Inhalt der einzelnen Dateien ist und welche Ausgabe gewünscht wird.
Jimmy
Die Zeichenfolge umfasst mehrere Zeilen. Ich ignoriere eher das Leerzeichen beim Abgleichen / Ersetzen, da es möglicherweise nicht alle absolut gleich sind, aber es ist keine große Sache, wenn ich nur 1: 1-Abgleiche (Zeilenvorschübe und alle) mache.
Ventsyv

Antworten:

12

Ersetzen Sie "Some ... \ n ... Thing" durch den Inhalt der Datei "new" in einer oder mehreren Eingabedateien

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
  1. -i um input.txt direkt zu ändern
  2. -p0 schlürfen Eingabedatei Datei und drucken Sie es am Ende
  3. s/regexp/.../s in regulärem Ausdruck .ist.|\n
  4. s/.../exp/e ersetzt durch eval(exp)
  5. neu - eine Datei mit dem Ersetzungstext (Dies ist ein völlig anderer Text)
  6. Wenn es nützlich ist, können Sie den Originaltext erweitern s/Some text\n...\n...thing\n/...
Joao
quelle
Wie kann ich dasselbe mit einer Datei namens say "before" tun, um nach dem (mehrzeiligen) Inhalt dieser Datei zu suchen? Ich habe es versucht, aber es funktioniert nicht.
Kvothe
@Kvothe, wir brauchen mehr Details ... Vorausgesetzt, dass "vor" keine besonderen Zeichen hat, können Sie versuchenperl -i -p0e ' $b= `cat before`; s/$b/Some thing\n/se' input.txt ...
JJoao
Und vorausgesetzt, das "Vorher" enthält alle Sonderzeichen (neue Zeilen, Schrägstriche, Klammern) mit Ausnahme von "und".
Kvothe
5
sed -e :n -e '$!N;/\n.*\n/!{$!bn
};  s/some text,\n* *something else\n* *another thing/this is completely\
different text/;P;D' <infile

Ich fürchte, Sie werden es schwer haben, eine Lösung zu finden, die zu Ihnen passt, bis Sie eine konkrete Beschreibung des Problems gefunden haben - aber dafür ist die Qualitätssicherung meines Erachtens am besten geeignet. Vielleicht haben Sie so eine Idee - es werden immer 3 Zeilen gleichzeitig im Musterbereich belassen - mit einem Lookahead von 2 Zeilen - während Sie jeweils nur eine Zeile vorwärts durch die Eingabedatei gleiten.

Es sollte in der Lage sein, mit Ihrer Zeichenfolge übereinzustimmen, unabhängig davon, ob sie mehrere Zeilen umfasst oder nicht - also bis zu drei. Es gibt jedoch keine Bestimmungen zum Spiegeln dieser Bestimmung in der Ersetzung - sie umfasst immer zwei Zeilen, wie geschrieben.

mikeserv
quelle
0

Nicht zu stark (weil die zweite Saite nicht geprüft wird, sich aber leicht einpendeln lässt) und nicht posix-kompilierbar, sondern sehr einfach:

sed '/^Some text/{:1;/another thing$/!{N;b 1}
     s/.*/this is completely\ndifferent text/g}' input.txt

Der erste Befehl fügt Zeilen aus einem Text hinzu, bis ein anderer Text getroffen wurde , und die zweite Zeile ändert ihn in einen anderen Text.

ANMERKUNG Die Einschränkung besteht darin, dass nach einigen Texten immer etwas anderes folgen muss .

Costas
quelle
Das Problem ist, dass die Zeichenfolge möglicherweise mehr als 2 Zeilen (bis zu einem Dutzend oder so) enthält und andere Dinge, die möglicherweise
maskiert
@ventsyv Es gibt kein Problem mit der Anzahl der Zeilen oder Trennzeichen - Skript überprüft nur den Anfang und das Ende. Es ist völlig ausreichend, wenn die Startzeichenfolge ausnahmsweise den zu ändernden Text markieren kann . Wenn dies nicht der Fall ist, zeigen Sie das Eingabebeispiel, um ein korrektes Muster zu erstellen.
Costas