Wie kann ich sed oder ex verwenden, um einen Block (mehrzeiligen Code) durch einen neuen Textblock (Code) zu ersetzen?

9

Ich muss einen großen Textblock (Shell-Skriptcode) in einer Datei durch einen anderen Textblock ersetzen.

Ich bin beeindruckt von Wie kann ich sed verwenden, um eine mehrzeilige Zeichenfolge zu ersetzen? beantwortet von antak und Multi-Line-Ersatz beantwortet von Bruce Ediger

Aber ich habe einige Probleme damit.

  1. antak hat bereits in seiner Antwort erwähnt, dass das Streaming der gesamten Datei ( 1h;2,$H;$!d;g;) in den Puffer für große Dateien nicht ratsam ist, da dadurch der Speicher überlastet wird.

  2. Ich weiß, seddass mit der Blockfunktion der Text außerhalb des Blocks unverändert beibehalten werden kann. Ich möchte diese Funktion verwenden. Aber wenn ich benutze,

    sed -i '/marker1/,/marker2/s/.*/new text (code)/' filename
    

Für jeden Stream wird wiederholt neuer Text (Code) eingefügt. Daher muß ich den visuellen Block als einen Strom machen, etwas mit ähnlich zu dem, was vorgeschlagen Antak früher, aber für den Block (nicht für ganze Datei).

  1. Wie von Bruce Ediger erwähnt, kann die Append-Funktion ausprobiert werden, exdie mit aend with .(dot) beginnt , aber mein neuer Text (code) enthält Zeilen, die mit dot beginnen, was als Punkt der Append-Syntax betrachtet werden kann. Wie kann ich es in dieser Situation verwenden?

  2. ex's dd' Anzahl der Zeilen 'kann mehrere Zeilen löschen, aber wenn ich einen Block zwischen / marker1 / und / marker2 / habe, dessen Anzahl nicht festgelegt (variierend) ist, muss er durch neuen Text (Code) ersetzt werden es?

Gibies
quelle
Ich finde Ihre Verwendung des Begriffs "visuelle Blockade" ungewöhnlich und verwirrend. Meinen Sie einfach einen Block (eine Gruppe) aufeinanderfolgender, vollständiger Zeilen?
Scott
Ja, ich bearbeite die Frage, um Verwirrung zu vermeiden.
Gibies
Was ist die Quelle für den Ersatztext? Ist es in einer Datei oder "nur im Kopf des Programmierers"?
don_crissti
Dies dient zum situativen Patchen eines Shell-Skripts. Daher ist die Quelle für den Ersatztext der Verstand des Programmierers (oder ein Masterskript, auf dem sedoder der exBefehl funktioniert).
Gibies
Don Crissti Ich hätte rden Befehl read file verwendet, um den Text aus einer anderen Datei zu kopieren, wenn sich die Quelle für den Ersatztext in einer Datei befindet.
Gibies

Antworten:

10

Ich schlage vor , mit dem c hange - Befehl (die im wesentlichen a d elete mit einem gekoppelten einem PPEND, obwohl die append nur für die letzte Zeile in dem Bereich, der genau angewandt wird , was Sie wollen hier):

sed -i '/marker1/,/marker2/c\
New text 1\
New text 2' filename

Hier wird die sedSyntax von GNU für die direkte Bearbeitung verwendet ( -i). Dieser cBefehl ist ansonsten Standard und portabel. GNU sedunterstützt:

sed '/marker1/,/marker2/cNew text 1\
New text 2' filename

als nicht standardmäßige Erweiterung.

Zeilenumbrüche und Backslash-Zeichen müssen im Ersatztext (mit Backslash) maskiert werden.

G-Man sagt "Reinstate Monica"
quelle
Der Änderungsbefehl funktioniert sowohl für beide sedals auch für alle exgleichermaßen. Vielen Dank.
Gibies
Gibt es eine Möglichkeit, "\" zu vermeiden und hier das Dokument zu verwenden, sedwie im Fall der exvon Bruce Ediger in " Mehrzeiliges Ersetzen" vorgeschlagenen Syntax .
Gibies
Sie würden die Backslashes nicht benötigen, wenn Sie den rBefehl verwenden, der in anderen Antworten auf diese Frage beschrieben wird. Ich bin mir nicht sicher, wie Sie ein Dokument hier verwenden würden sed.
G-Man sagt "Reinstate Monica"
8

Mit GNU sed

So ersetzen Sie Zeilen, die eine Zeilenübereinstimmung beginnen 3und mit einer Zeilenübereinstimmung fortfahren 5mit New Code:

$ seq 8 | sed '/3/,/5/{/5/ s/.*/New Code/; t; d}'
1
2
New Code
6
7
8

Bei Zeilen im Bereich /3/,/5/testen wir, ob die Zeile übereinstimmt 5(was bedeutet, dass dies die letzte Zeile in der Gruppe ist), und wenn ja, ersetzen wir sie durch Einfügen New Code. Wenn die Ersetzung vorgenommen wurde, weist der tBefehl sed an, zum Ende der Befehle zu springen (in diesem Fall New Codewird gedruckt). Wenn nicht, weist der dBefehl sed an, die Zeile zu löschen.

Alle anderen Zeilen werden normal gedruckt.

Um die Datei an Ort und Stelle zu ändern, kann die -iOption verwendet werden:

sed -i.bak '/3/,/5/{/5/ s/.*/New Code/; t; d}' file

Mit awk

So machen Sie dasselbe mit awk:

$ seq 8 | awk '/3/,/5/{if (!f)print "New Code"; f=1; next}; 1'
1
2
New Code
6
7
8

Der Befehl awk behandelt Zeilen im Bereich /3/,/5/speziell. Bei Zeilen in diesem Bereich testen wir, ob fNull ist (dh ob dies der !fFall ist). Wenn dies der Fall ist, drucken wir New Codeund setzen fauf 1. Anschließend überspringen wir den Rest der Befehle und springen zur nextZeile.

Bei Zeilen außerhalb des Bereichs /3/,/5/wird kein Sprung ausgeführt, und 1die Zeile wird gedruckt. Im Detail 1ist eine Bedingung. Da 1nicht Null ist, wird die Bedingung als wahr ausgewertet. Da der Bedingung keine Aktion zugeordnet ist, wird die Standardaktion ausgeführt, bei der die Zeile gedruckt wird. Daher 1ist die Abkürzung für Print-the-Line.

Um eine Datei an Ort und Stelle zu ändern, kann die -i inplaceOption mit GNU awk4.1 oder höher verwendet werden:

awk -i inplace '/3/,/5/{if (!f)print "New Code"; f=1; next} 1' file
John1024
quelle
cool. Ich bin nicht gut darin awk, könnten Sie bitte etwas Ihren awkAusdruck erklären
Rahul
1
@ Rahul Sicher. Ich habe eine Erklärung des awk-Codes hinzugefügt.
John1024
1
Danke John Genau das habe ich gesucht.
Gibies
Sehr einfach, Block zu entfernen und dann neue zur letzten Zeile hinzuzufügen:sed '/3/,/4/d;/5/cNew Code' awk '/5/{print "New Code"}/3/,/5/{next}1'
Costas
1

Basierend auf der obigen Diskussion habe ich eine Lösung mit ex

seq 15 > test1.txt
ex test1.txt << EOEX
/^7/,/^9/c
abcd
123
.xyz
hfr4
.
w!
q
EOEX
cat test1.txt

Das obige gibt

1
2
3
4
5
6
abcd
123
.xyz
hfr4
10
11
12
13
14
15

Vielen Dank an g-man , dass er mich auf den Änderungsbefehl aufmerksam gemacht und Klarheit über dot gegeben hat. Beide sedund haben eine exfast ähnliche Syntax für den Änderungsbefehl (auch für den Löschbefehl, den Befehl zum Anhängen usw.).

Gibies
quelle