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
| Command | Effect | Portable? |
|---|---|---|
d | delete the pattern space, start the next cycle | POSIX |
D | delete up to the first embedded newline, restart the script without reading | POSIX |
i\ text | insert text before the current line | POSIX |
a\ text | append text after the current line | POSIX |
c\ text | replace the selected line, or a whole range, with text | POSIX |
y/abc/xyz/ | transliterate, character for character | POSIX |
r file | read file in after the current line | POSIX |
R file | read one line of file in after the current line | GNU only |
q | print, then quit | POSIX |
Q | quit without printing | GNU only |
q N / Q N | quit with exit status N | GNU only |
z | zap, empty the pattern space | GNU only |
= | print the current line number on its own line | POSIX |
l | print the pattern space unambiguously, escapes visible | POSIX |
F | print the current input file name | GNU 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