SED processes one line at a time by default, but the N, P, and D commands unlock multi-line capability. They let you accumulate lines into the pattern space, match and transform text that spans multiple lines, and implement a sliding two-line window — patterns that are impossible without these commands.
1
N, P, D — the multi-line trio
BASH
# N — append Next line to pattern space (joined with \n)
# P — Print up to first \n in pattern space
# D — Delete up to first \n, restart cycle without reading new line
# ── Join every two lines ──────────────────────────────────
sed 'N; s/\n/ /'
# Reads line 1, appends line 2 (with \n), replaces \n with space
# Input: line1\nline2\nline3\nline4
# Output: line1 line2\nline3 line4
# ── Join continuation lines (backslash-continued) ─────────
# Input: a very long \
# command here
sed ':a; /\\$/{N; s/\\\n//; ta}'
# Label :a, if line ends in \, append next, strip \+newline, loop
# ── Delete blank lines but keep paragraph breaks ──────────
sed '/^$/{ N; /^\n$/d }'
# Collapse sequences of 2+ blank lines to 1
# ── Match a pattern spanning two adjacent lines ───────────
sed -E '/^HEADER/{N; s/HEADER\nVALUE/NEWHEADER\nNEWVALUE/}'
# ── Sliding two-line window — match line N+1 when N matches ─
sed -n '/^ERROR/{N; p}'
# Print ERROR line plus the line that follows it
2
Joining and collapsing multi-line constructs
BASH
# ── Collapse a multi-line block to one line ───────────────
# Input:
# server {
# listen 80;
# server_name example.com;
# }
sed '/^server {/,/^}/{H; /^}/{ g; s/\n/ /g; s/ */ /g; p; d }; d'
# → server { listen 80; server_name example.com; }
# ── Join wrapped log lines ────────────────────────────────
# Lines starting with whitespace are continuations of previous
# 2026-05-01 ERROR: disk
# full on /data
sed -E ':a; N; s/\n[[:space:]]+/ /; ta'
# → 2026-05-01 ERROR: disk full on /data
# ── Remove blank lines between paragraphs ─────────────────
sed '/^$/d' # delete ALL blank lines
sed -E ':a; /^\n*$/{ $d; N; ba }' # squeeze multiple blanks to one
# ── Add blank line between records ───────────────────────
sed '/^---$/G' # add blank after --- separator
sed '/pattern/G' # add blank after every match
# ── Process paragraph mode (blank-line separated) ─────────
# Print only paragraphs containing ERROR
sed -n '/./,/^$/{ H; /^$/{ x; /ERROR/p } }; ${H; x; /ERROR/p}' file.txt
3
Matching and editing across line boundaries
BASH
# ── Delete a line and the following line ──────────────────
sed '/PATTERN/{N; d}'
# Delete matching line + next line
# ── Delete a line and ALL following until blank line ───────
sed '/PATTERN/,/^$/d'
# ── Insert a line before the line after a match ───────────
sed '/MATCH/{n; i\INSERTED_BEFORE_NEXT
}'
# n reads next line into pattern space (different from N)
# ── Replace a key=value that may be on the next line ──────
# Config where key and value may be split:
# key =
# old_value
sed '/^key =/{N; s/key =\n[[:space:]]*.*/key = new_value/}'
# ── Extract a block (inclusive, first match only) ─────────
sed -n '/^BEGIN/,/^END/p' file.txt
# ── Extract block EXCLUDING delimiters ────────────────────
sed -n '/^BEGIN/{n; :loop; /^END/q; p; n; b loop}' file.txt
# ── Squash duplicate adjacent lines (like uniq) ───────────
sed '$!N; /^\(.*\)\n\1$/!P; D'
# Reads two lines; if identical, drops first; otherwise prints
4
Practical multi-line SED patterns
BASH
# ── Reformat a multi-line certificate block to one line ───
sed ':a; /^-----BEGIN/,/^-----END/{ N; s/\n//; ta }' cert.pem
# ── Strip XML/HTML tags spanning multiple lines ────────────
sed ':a; N; s/<[^>]*>//g; ta' page.html
# ── Convert a multi-line address block to CSV ─────────────
# Name: John → John,42 Main St,Chennai
# Address: 42 Main St
# City: Chennai
sed '/^Name:/{
N; N
s/Name: \(.*\)\nAddress: \(.*\)\nCity: \(.*\)/\1,\2,\3/
}'
# ── Process Java/Python stack traces ─────────────────────
# Join exception + first stack frame onto one line
grep -A1 "Exception" app.log | sed '/^--$/d; N; s/\n/ → /'
# ── Wrap long lines at 80 chars (fold) ────────────────────
sed 's/.\{80\}/&\n/g' # insert newline every 80 chars
vriddh@prod-01:~/scripts$printf 'line1\nline2\nline3\nline4\n' | sed 'N; s/\n/ /'
line1 line2
line3 line4
vriddh@prod-01:~/scripts$printf 'cmd \\\narg1 \\\narg2\n' | sed ':a; /\\$/{N; s/\\\n//; ta}'
cmd arg1 arg2
vriddh@prod-01:~/scripts$sed -n '/^ERROR/{N; p}' app.log | head -4
ERROR DB connection failed
at pool.connect (db.js:42)
█
N vs n — Lowercase
n prints the current pattern space, clears it, and reads the next line. Uppercase N appends the next line to the current pattern space separated by \n without printing first. Use N when you need both lines simultaneously. Use n when you want to skip to the next line and process it independently.✔ Multi-line SED rules — Use
N to build a two-line sliding window. Use :label; ...; b label for loops that consume until a condition is met. After N, use \n in patterns to match the embedded newline in the pattern space. Use P and D for pipeline-style processing where lines are consumed one at a time from a buffered multi-line space. Prefer AWK for complex multi-line logic — SED becomes unreadable quickly.