sed: hold space and multi-line editing

grep, sed & awk · Advanced · 15 min

Joining continuation lines or editing a line based on its neighbour needs sed's multi-line commands.

Normally sed sees one line at a time. A few commands widen the view:

  • N appends the next input line to the pattern space, separated by \n.
  • P prints up to the first newline; D deletes up to the first newline and restarts the cycle without reading a new line. N;P;D is the sliding two-line window.
  • The hold space is a second buffer that persists between lines. h copies the pattern space into it, H appends, g copies it back, G appends it to the pattern space, x swaps the two.
  • :label defines a label, b label branches to it, and t label branches only if a substitution succeeded since the last input line or t.

Common uses:

  • sed ':a; /\\$/ { N; s/\\\n//; ba }' joins lines ending in a backslash with the next.
  • sed -n '1!G; h; $p' reverses a file (what tac does).
  • GNU sed's -z treats the whole input as NUL-separated, so a file without NULs becomes one big "line" that you can edit with regexes containing \n.

This is where sed programs become hard to read. If the logic needs more than a couple of these commands, an awk script, which has real variables and if, is usually clearer and easier to maintain.

Example

# join lines ending in a backslash with the next line
printf 'cmd --a \\\n  --b\nnext\n' | sed -e ':a' -e '/\\$/{N; s/\\\n *//; ba' -e '}'
# cmd --a --b
# next

# reverse a file: prepend each line to the hold space, print at the end
printf '1\n2\n3\n' | sed -n '1!G; h; $p'          # 3 / 2 / 1

# print each line that comes right before a line containing ERROR
printf 'a\nb\nERROR\nc\n' | sed -n '$!N; /\nERROR/P; D'     # b

# -z: replace the newline between two lines
printf 'key=\nvalue\n' | sed -z 's/=\n/=/'           # key=value

Remember

  • N appends the next line; P and D work on the first line of the buffer
  • h/H/g/G/x move text between the pattern space and the hold space
  • Switch to awk once a sed program needs more than a few of these

Watch out for

  • Forgetting that N on the last line prints and exits in GNU sed but behaves differently elsewhere; guard with $!N.

Check yourself

  1. What does the D command do when the pattern space contains a newline?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.gnu.org/software/sed/manual/sed.html#Multiline-techniques