sed Cheatsheet

Delete Insert and Change

Use this sed reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

The command set

CommandEffectPortable?
ddelete the pattern space, start the next cyclePOSIX
Ddelete up to the first embedded newline, restart the script without readingPOSIX
i\ textinsert text before the current linePOSIX
a\ textappend text after the current linePOSIX
c\ textreplace the selected line, or a whole range, with textPOSIX
y/abc/xyz/transliterate, character for characterPOSIX
r fileread file in after the current linePOSIX
R fileread one line of file in after the current lineGNU only
qprint, then quitPOSIX
Qquit without printingGNU only
q N / Q Nquit with exit status NGNU only
zzap, empty the pattern spaceGNU only
=print the current line number on its own linePOSIX
lprint the pattern space unambiguously, escapes visiblePOSIX
Fprint the current input file nameGNU only

Delete

d ends the cycle immediately, so any command after it never runs on that line.

sed '/^#/d'          file   # drop comment lines
sed '/^$/d'          file   # drop blank lines
sed '/^[[:space:]]*$/d' file  # drop whitespace-only lines too
sed '1d'             file   # drop the header
sed '$d'             file   # drop the last line
sed '1,10d'          file   # drop the first ten lines
sed '/BEGIN/,/END/d' file   # drop a block
sed '/keep/!d'       file   # keep ONLY matching lines, like grep

D is different and only useful with a multi-line pattern space. It deletes through the first newline and restarts the script on what is left, without reading new input. That is the engine behind the squeeze-blank-lines idiom.

# collapse runs of blank lines into one, GNU spelling
gsed '/^$/{N;/^\n$/D}' file
# same thing, portable (note the -e split so } is not glued to D)
sed -e '/^$/{N;/^\n$/D' -e '}' file

Insert, append, change

These three take text, and the way you attach that text is the biggest BSD versus GNU difference after -i.

# GNU only: text on the same line
gsed '1i HEADER'      file
gsed '$a FOOTER'      file
gsed '3c REPLACED'    file

# POSIX form: backslash, newline, then the text. Works everywhere
sed '1i\
HEADER' file

# same thing from a shell one-liner, using ANSI-C quoting
sed $'1i\\\nHEADER' file
sed $'$a\\\nFOOTER' file

macOS sed rejects 1i HEADER outright with command i expects \ followed by text. It also rejects the widely-copied sed -e '1i\' -e 'HEADER' trick.

More rules for the text argument:

- Continue onto more lines by ending each one with a backslash. - Leading whitespace survives in the POSIX backslash-newline form on both platforms. It is stripped in GNU's one-line 1i text form, where you escape the first space as 1i\ text to keep it. - a output appears even if a later d deletes the line, because it is queued for after the cycle. - c on a range prints the text once and deletes the whole range. c with a one-line address prints it per line.

sed $'2,4c\\\nONE LINE' five.txt      # l1, ONE LINE, l5
sed $'/^#/c\\\n# redacted' conf       # every comment line replaced individually

Change versus substitute

sed 's/.*/new/'   file   # rewrites every line's content
sed $'c\\\nnew'   file   # same visible result, different mechanism

Use c when you want to replace whole lines matched by an address, and s when you are rewriting part of a line. c cannot reference the old text, there is no &.

Transliterate with y

y maps characters one to one. Both sides must be the same length, and there are no ranges and no classes.

printf 'abc\n'   | sed 'y/abc/xyz/'      # xyz
printf 'a-b_c\n' | sed 'y/-_/__/'        # a_b_c
printf 'hello\n' | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'

y/a-z/A-Z/ does not work, the hyphen is literal. Use tr 'a-z' 'A-Z' for ranges, it is the right tool.

Reading files in

sed '1r header.txt'      file   # insert a file after line 1
sed '$r footer.txt'      file   # append a file at the end
sed '/MARKER/r block.txt' file  # insert a file after each marker
sed '/MARKER/{r block.txt
d;}'                     file   # replace the marker with the file
gsed '1R lines.txt'      file   # GNU: one line of lines.txt per match

- r is queued like a, so it lands after the current line no matter where the command sits in the script. - A missing file is not an error, r just contributes nothing. - To insert a file before a line, r cannot help. Use sed -e '/M/{' -e 'r block.txt' -e 'd' -e '}' with the marker acting as the anchor, or reach for awk.

Quitting early

sed '10q'            file   # first 10 lines, like head -10
sed '/ERROR/q'       file   # everything up to and including the first error
gsed '/ERROR/Q'      file   # everything BEFORE the first error, GNU only
sed -n '/ERROR/{p;q;}' file # just the first error line, portable
gsed '/FATAL/q3'     file   # GNU: quit with status 3

q on a huge file is the difference between a millisecond and a minute, since sed stops reading. head -n does the same but q composes with an address.

# print lines 500000-500010 of a 10 GB file without reading the rest
sed -n '500000,500010p; 500011q' huge.log