Sed: Mehrzeilige Ersetzungen mit Hold Space und Pattern Space
AI generated
$_
#!/
sed · Textverarbeitung · Shell-Scripting · Linux
Sed: Mehrzeilige Ersetzungen
mit Hold Space und Pattern Space meistern

Wer sed nur zeilenweise mit s/alt/neu/ einsetzt, stoesst bei Config-Bloecken, XML-Fragmenten und mehrzeiligen Log-Eintraegen schnell an Grenzen. Hold Space und Pattern Space geben sed die Faehigkeit, mehrere Zeilen gleichzeitig zu betrachten und gezielt als zusammenhaengenden Block zu ersetzen, ganz ohne Perl oder Python.

18 Min. Lesezeit Hold Space · N-Schleife · Adressbereiche · sed -z GNU sed 4.x · BSD sed · Linux

1. Warum einzeilige sed-Kommandos an Grenzen stossen

Der klassische Aufruf sed 's/alt/neu/' datei.txt arbeitet strikt zeilenweise: sed liest eine Zeile in den Pattern Space, wendet das Kommando an, gibt das Ergebnis aus und liest die naechste Zeile. Fuer einfache Textersetzungen reicht das vollkommen aus. Sobald aber eine Ersetzung sich ueber mehrere Zeilen erstreckt, etwa ein XML-Element, das ueber drei Zeilen laeuft, oder ein mehrzeiliger Kommentarblock in einer Config-Datei, versagt dieser einzeilige Ansatz vollstaendig, weil sed die vorherige Zeile beim Verarbeiten der naechsten schlicht nicht mehr kennt.

Genau hier setzt sed mehrzeilige Ersetzungen mit dem sogenannten Hold Space an. sed haelt intern zwei Puffer: den Pattern Space, der die aktuell verarbeitete Zeile enthaelt, und den Hold Space, einen zusaetzlichen Speicherbereich, in dem Zeilen zwischengelagert werden koennen. Mit gezielten Kommandos lassen sich Zeilen zwischen beiden Puffern verschieben, zusammenfuehren und gemeinsam bearbeiten. Damit wird sed zu einem vollwertigen Werkzeug fuer sed mehrzeilige Ersetzungen, ohne dass ein Wechsel zu Perl oder Python noetig ist.

In der Praxis begegnet einem dieses Problem regelmaessig bei Deploy-Skripten, die Nginx-Konfigurationen patchen, bei der Bereinigung von Log-Dateien mit mehrzeiligen Stacktraces oder beim automatisierten Umschreiben von Docker-Compose-Bloecken. Wer sed mehrzeilige Ersetzungen einmal verstanden hat, kann diese Aufgaben in einer einzigen Kommandozeile loesen, statt ein komplettes Skript in einer anderen Sprache zu schreiben.

2. Hold Space verstehen: N, h, H, g, G, x

Die sechs Kommandos N, h, H, g, G und x bilden das Fundament jeder sed mehrzeilige Ersetzungen-Aufgabe. N haengt die naechste Zeile an den aktuellen Pattern Space an, getrennt durch ein eingebettetes Newline. h kopiert den Pattern Space in den Hold Space und ueberschreibt dessen Inhalt, waehrend H den Pattern Space an den bestehenden Hold-Space-Inhalt anhaengt. Umgekehrt kopiert g den Hold Space in den Pattern Space, G haengt ihn an, und x tauscht beide Puffer komplett aus.

Ein typisches Muster fuer sed mehrzeilige Ersetzungen: Mit 1h wird die erste Zeile in den Hold Space kopiert, mit H werden alle folgenden Zeilen angehaengt, und am Ende der Datei holt ${g;p} den gesamten gesammelten Text zurueck und gibt ihn aus. Dieses Muster wird oft genutzt, um eine komplette Datei in den Hold Space zu laden und anschliessend mit einem einzigen Ersetzungskommando ueber den gesamten Inhalt zu arbeiten, statt zeilenweise vorzugehen.


#!/usr/bin/env bash
# sed hold space basics — copy, append, swap
set -euo pipefail

# Load the entire file into hold space, then work on it as one block
sed -n '1h; 1!H; ${g; p}' config.conf > /tmp/whole-file-as-block.txt

# Practical example: join every two lines into one (key + value pairs)
printf 'name\nAcme Corp\nport\n8080\n' | sed 'N; s/\n/=/'
# Output:
# name=Acme Corp
# port=8080

# Swap pattern and hold space to compare current line with previous one
sed -n 'x; $p; x; 1!p' access.log | tail -n +2

3. Zeilen gezielt zusammenfassen: die N-Schleife mit :loop und b

Das Kommando N allein zieht nur eine einzige zusaetzliche Zeile in den Pattern Space. Um beliebig viele Zeilen zusammenzufassen, etwa einen kompletten mehrzeiligen Kommentarblock oder einen Stacktrace unbekannter Laenge, braucht man eine Schleife. Das sed mehrzeilige Ersetzungen-Pattern dafuer definiert eine Sprungmarke mit :loop, zieht mit N die naechste Zeile hinzu und springt mit b loop zurueck, solange eine Bedingung erfuellt ist, etwa solange die Zeile nicht mit einem bestimmten Muster endet.

Wichtig ist dabei die Behandlung der letzten Zeile: Wenn N am Dateiende aufgerufen wird und keine weitere Zeile mehr existiert, verhaelt sich GNU sed anders als POSIX sed. GNU sed druckt in diesem Fall den aktuellen Pattern Space noch aus und beendet das Skript, waehrend striktes POSIX-sed das Skript ohne Ausgabe abbricht. Wer portable Skripte fuer sed mehrzeilige Ersetzungen schreiben will, sollte das explizit mit $!N abfangen, sodass am letzten Zeilenende kein N mehr versucht wird.


#!/usr/bin/env bash
set -euo pipefail

# Join an unknown number of continuation lines ending in backslash
# into a single logical line — typical for shell or Makefile continuations
sed -e ':loop' -e '/\\$/{N; s/\\\n//; b loop}' Makefile.fragment

# Collapse multi-line log entries that start with a timestamp
# into single lines, joining continuation lines with a space
sed -E ':loop
/^[0-9]{4}-[0-9]{2}-[0-9]{2}/!{
  N
  s/\n(  )/ /
  b loop
}' app.log

4. Mehrzeilige Bloecke ersetzen: Adressbereiche mit /START/,/END/

Adressbereiche sind das direkteste Mittel fuer sed mehrzeilige Ersetzungen, wenn ein klar erkennbarer Anfang und ein klar erkennbares Ende existieren. Die Syntax /START-Muster/,/END-Muster/ definiert einen Bereich, innerhalb dessen ein Kommando angewendet wird. Damit lassen sich ganze Bloecke einer Config-Datei loeschen, ersetzen oder markieren, ohne dass man die genauen Zeilennummern kennen muss, was fuer Skripte entscheidend ist, die auf unterschiedlich langen Eingabedateien laufen sollen.

Ein haeufiger Anwendungsfall bei sed mehrzeilige Ersetzungen ist das Ersetzen eines gesamten Server-Blocks in einer Nginx-Konfiguration oder eines Abschnitts zwischen zwei Marker-Kommentaren wie # BEGIN AUTOGENERATED und # END AUTOGENERATED. Der Bereich wird zunaechst mit d geloescht, danach fuegt man mit a oder r den neuen Inhalt an der richtigen Stelle wieder ein. Diese Technik ist robuster als eine reine Zeilennummern-basierte Loesung, weil sie funktioniert, egal wie sich die Datei drumherum veraendert.


#!/usr/bin/env bash
set -euo pipefail

# Replace an entire marked block between two comment markers
# with fresh content from a separate file
sed -e '/# BEGIN AUTOGENERATED/,/# END AUTOGENERATED/{
  /# BEGIN AUTOGENERATED/r generated-block.txt
  /# BEGIN AUTOGENERATED/!{/# END AUTOGENERATED/!d}
}' nginx.conf > nginx.conf.new

# Delete a whole XML element spanning multiple lines
sed '/<deprecated-feature>/,/<\/deprecated-feature>/d' features.xml

# Print only what is inside a marked range (inclusive)
sed -n '/^-- migration:2024_08/,/^-- migration:2024_09/p' schema.sql

5. Praxisbeispiele: Config-Dateien, XML-Fragmente, Log-Bloecke

In Deploy-Skripten kommt sed mehrzeilige Ersetzungen haeufig zum Einsatz, um Umgebungsvariablen-Bloecke in Docker-Compose-Dateien auszutauschen, ohne die YAML-Struktur drumherum zu beschaedigen. Ein typisches Muster: Der gesamte environment:-Block einer bestimmten Service-Definition wird per Adressbereich geloescht und durch neu generierte Zeilen ersetzt, die aus einer .env-Datei erzeugt wurden. Das funktioniert zuverlaessig, solange Einrueckung und Struktur der YAML-Datei konsistent bleiben.

Bei Log-Dateien mit mehrzeiligen Java- oder PHP-Stacktraces ist die N-Schleife das Mittel der Wahl, um zusammengehoerige Zeilen zu einem einzigen Datensatz zusammenzufassen, bevor sie an grep oder awk weitergereicht werden. Ohne diesen Zwischenschritt wuerde jede Stacktrace-Zeile als eigenstaendiger Log-Eintrag behandelt, was Auswertungen wie Fehlerzaehlungen pro Exception-Typ verfaelscht. sed mehrzeilige Ersetzungen loesen dieses Problem, indem sie den kompletten Block vor der Weiterverarbeitung zu einer Zeile verschmelzen.

Ein drittes Praxisbeispiel betrifft XML- und HTML-Fragmente in Templates, bei denen ein einzelnes Tag ueber mehrere Zeilen mit Attributen verteilt ist. Statt fragiler regulaerer Ausdruecke, die nur eine Zeile abdecken, liest man mit N so viele Zeilen ein, bis das schliessende > gefunden wurde, und wendet die Ersetzung dann auf den kompletten, zusammengefuegten Tag-Block an. Das ist deutlich robuster als der Versuch, ein mehrzeiliges Tag mit einem einzeiligen Ausdruck zu erwischen.

6. sed -z fuer Null-Byte-getrennte Verarbeitung ganzer Dateien

Die Option -z (bei GNU sed auch --null-data) aendert den Datensatz-Trenner von Newline auf das Null-Byte. Das bedeutet: sed behandelt die komplette Eingabe faktisch als einen einzigen Datensatz, solange keine Null-Bytes enthalten sind, was sed mehrzeilige Ersetzungen ueber Zeilengrenzen hinweg drastisch vereinfacht, weil der Punkt . im regulaeren Ausdruck dann auch Newlines matcht.

Diese Technik eignet sich besonders fuer Ersetzungen, bei denen ein Muster garantiert nicht innerhalb einer einzelnen Zeile beginnt und endet, etwa ein mehrzeiliger Kommentarblock in Quellcode oder ein HTML-Kommentar, der sich ueber mehrere Zeilen erstreckt. Ohne -z muesste man dafuer eine N-Schleife bauen, mit -z reicht ein einziger s///-Ausdruck mit dem Modifikator s fuer DOTALL-Verhalten oder einer expliziten Newline im Suchmuster.


#!/usr/bin/env bash
set -euo pipefail

# Remove a multi-line HTML comment block spanning several lines
# treating the whole file as one record (null-separated)
sed -z 's/<!--.*-->//g' template.html > template.clean.html

# Replace a multi-line license header at the top of every source file
find src -name '*.php' -print0 | while IFS= read -r -d '' file; do
  sed -z -i 's/^\/\*.*\*\///' "$file"
done

# Note: -z reads the whole file into memory — avoid on very large files

7. Performance und Fallstricke bei grossen Dateien

Der grosse Vorteil von sed mehrzeilige Ersetzungen mit Hold Space gegenueber -z ist der Speicherverbrauch: Hold Space und Pattern Space arbeiten weiterhin zeilenweise beziehungsweise blockweise, waehrend -z die komplette Datei in den Arbeitsspeicher laedt. Bei Logdateien im Gigabyte-Bereich kann -z deshalb zu spuerbaren Verzoegerungen oder sogar Speicherproblemen fuehren, waehrend eine sauber konstruierte N-Schleife weiterhin streambasiert arbeitet und nur so viele Zeilen im Speicher haelt, wie fuer den aktuellen Block noetig sind.

Ein zweiter Performance-Fallstrick ist die unbegrenzte N-Schleife ohne Abbruchbedingung: Fehlt die Pruefung auf das Ende des Blocks, versucht sed immer weiter Zeilen anzuhaengen, bis entweder das Muster gefunden wird oder die Datei endet. Bei fehlerhaften Eingabedaten, in denen der Endmarker fehlt, kann das dazu fuehren, dass die komplette restliche Datei in einem einzigen riesigen Pattern Space landet. Ein zusaetzliches Sicherheitsnetz mit einer Zeilenzahl-Begrenzung oder einer expliziten Fehlermeldung bei fehlendem Endmarker verhindert dieses Verhalten in Produktionsskripten.

8. sed-Skripte debuggen: -n, das l-Kommando und Trockenlaeufe

Beim Debuggen komplexer sed mehrzeilige Ersetzungen hilft die Kombination aus -n (unterdrueckt automatische Ausgabe) und dem l-Kommando, das den aktuellen Pattern Space inklusive aller nicht druckbaren Zeichen und eingebetteter Newlines sichtbar macht. Ein eingebettetes Newline erscheint dabei als \n im Text, sodass man sofort erkennt, ob mehrere Zeilen tatsaechlich im Pattern Space zusammengefuehrt wurden oder ob die N-Schleife vorzeitig abgebrochen ist.

Ein zweiter praktischer Trick ist, das Skript zunaechst nur mit p statt einer echten Ersetzung laufen zu lassen, um zu pruefen, welche Zeilen ueberhaupt in den betreffenden Adressbereich fallen, bevor man scharf mit d oder s/// arbeitet. Wer sed mehrzeilige Ersetzungen in Produktionsskripten einsetzt, sollte zusaetzlich immer zuerst gegen eine Kopie der Datei testen und erst nach Verifikation mit -i in-place aendern, idealerweise mit -i.bak, um ein automatisches Backup zu erhalten.


#!/usr/bin/env bash
set -euo pipefail

# Debug: show embedded newlines and control characters explicitly
sed -n 'N; l' two-lines.txt

# Dry run: only print the matched range, do not delete or replace yet
sed -n '/# BEGIN/,/# END/p' nginx.conf

# Safe in-place edit with automatic backup
sed -i.bak -e '/# BEGIN AUTOGENERATED/,/# END AUTOGENERATED/d' nginx.conf
diff nginx.conf.bak nginx.conf

9. sed im Vergleich: Hold Space vs. awk vs. perl fuer mehrzeilige Aufgaben

Nicht jede mehrzeilige Textaufgabe ist mit sed mehrzeilige Ersetzungen gleich gut geloest. Ab einer gewissen Komplexitaet, etwa bei verschachtelten Bloecken oder wenn Zaehllogik noetig ist, lohnt sich der Blick auf Alternativen mit klareren Kontrollstrukturen.

Aufgabe sed Hold Space awk perl
Marker-Block ersetzen Sehr gut geeignet Umstaendlich Ueberdimensioniert
Beliebig lange Bloecke joinen Moeglich, aber unuebersichtlich Gut mit RS-Trick Sehr gut mit slurp mode
Verschachtelte Bloecke, Zaehler Nicht praktikabel Machbar mit Variablen Beste Wahl
Ganze Datei als DOTALL-Regex sed -z Nicht vorgesehen perl -0777
Verfuegbarkeit ohne Zusatzinstallation Immer vorhanden Immer vorhanden Meist vorhanden, nicht garantiert

Fuer klar abgegrenzte Marker-Bloecke und einfache Zeilen-Joins bleibt sed mehrzeilige Ersetzungen die schlankste Loesung, weil kein zusaetzlicher Interpreter noetig ist und das Kommando in jeder Deploy-Umgebung ohne weitere Abhaengigkeiten laeuft. Sobald aber Zaehllogik, verschachtelte Strukturen oder komplexe Bedingungen ins Spiel kommen, ist der Wechsel zu awk oder perl die pragmatischere Entscheidung, weil sich diese Faelle in reinem sed nur mit unverhaeltnismaessig viel Aufwand abbilden lassen.

Mironsoft

Shell-Automatisierung, Deploy-Skripte und Textverarbeitungs-Pipelines

Fragile Config-Patches durch robuste sed-Skripte ersetzen?

Wir bauen Deploy- und Wartungsskripte, die mehrzeilige Ersetzungen zuverlaessig, getestet und ohne manuellen Eingriff durchfuehren, egal ob Nginx-Configs, YAML-Bloecke oder Log-Bereinigung.

Skript-Review

Bestehende sed-Skripte auf Robustheit und Portabilitaet pruefen

Automatisierung

Config-Patches und Log-Bereinigung sicher in Deploy-Pipelines integrieren

Schulung

Hold Space, Adressbereiche und N-Schleifen im Team praxisnah vermitteln

10. Zusammenfassung

sed mehrzeilige Ersetzungen loesen ein Problem, an dem der zeilenweise Standardmodus von sed grundsaetzlich scheitert: Bloecke, die sich ueber mehrere Zeilen erstrecken, muessen als Ganzes betrachtet werden, um korrekt ersetzt, geloescht oder markiert zu werden. Hold Space und Pattern Space liefern dafuer mit N, h, H, g, G und x das noetige Werkzeug, Adressbereiche mit /START/,/END/ machen Marker-basierte Bloecke robust gegenueber Aenderungen in der restlichen Datei.

Fuer sehr grosse Dateien lohnt sich der Blick auf den Speicherverbrauch: Streambasierte N-Schleifen sind sparsamer als sed -z, das die komplette Datei einliest. Wer sed mehrzeilige Ersetzungen in Produktionsskripten einsetzt, sollte konsequent zuerst mit -n und dem l-Kommando testen, bevor mit -i destruktiv am Original gearbeitet wird. Ab einer gewissen Komplexitaet mit verschachtelten Strukturen ist der Wechsel zu awk oder perl die pragmatischere Wahl.

Sed mehrzeilige Ersetzungen: Das Wichtigste auf einen Blick

Hold Space Kommandos

N haengt Zeilen an, h/H speichern in den Hold Space, g/G holen zurueck, x tauscht beide Puffer.

N-Schleife

:loop; /muster/!{N; b loop} fasst beliebig viele Zeilen zusammen, immer mit $!N gegen Dateiende absichern.

Adressbereiche

/START/,/END/ markiert Bloecke robust, unabhaengig von konkreten Zeilennummern.

sed -z

Behandelt die ganze Datei als einen Datensatz, praktisch fuer DOTALL-Matches, aber speicherintensiver bei grossen Dateien.

11. FAQ: Sed mehrzeilige Ersetzungen

1Pattern Space vs. Hold Space?
Pattern Space enthaelt die aktuell verarbeitete Zeile oder den Block. Hold Space ist ein Zwischenspeicher fuer spaeteren Zugriff mit g oder G.
2Mehrere Zeilen zusammenfassen?
N haengt die naechste Zeile an, getrennt durch ein eingebettetes Newline. Danach ersetzt s/\n/ / das Newline durch ein Trennzeichen.
3Block zwischen Markern loeschen?
Adressbereich nutzen: sed '/START/,/END/d' datei.txt loescht alle Zeilen inklusive der Marker.
4N-Schleife bei letzter Zeile?
GNU und POSIX sed verhalten sich unterschiedlich. Mit $!N wird N nur bei vorhandener naechster Zeile ausgefuehrt, das macht das Skript portabel.
5sed -z statt N-Schleife?
Fuer Muster ohne bekannte Zeilenbindung geeignet. Bei sehr grossen Dateien ist eine N-Schleife sparsamer, weil -z die ganze Datei einliest.
6Zusammenfuehrung debuggen?
sed -n 'N; l' zeigt eingebettete Newlines als \n. Fehlt das \n im Output, wurden die Zeilen nicht zusammengefuehrt.
7sed -i sicher fuer Produktion?
Nur mit vorherigem Test. sed -i.bak legt automatisch ein Backup an, vorher immer mit -n gegen eine Kopie pruefen.
8Verschachtelte Bloecke moeglich?
Praktisch nicht zuverlaessig, sed hat kein Zaehlkonzept fuer Verschachtelung. awk oder perl mit expliziter Zaehlvariable sind hier besser geeignet.
9h/H vs. g/G?
h ueberschreibt den Hold Space, H haengt an. g ueberschreibt den Pattern Space, G haengt an. Kleinbuchstabe ueberschreibt, Grossbuchstabe haengt an.
10Wann zu awk oder perl wechseln?
Sobald Zaehllogik, Verschachtelung oder komplexe Zustandsverwaltung noetig sind. awk und perl bieten klarere Kontrollstrukturen dafuer.