sed Cheatsheet

One-Liners

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

Printing and selecting

sed -n '5p'            file   # print line 5
sed -n '2,4p'          file   # lines 2 through 4
sed -n '$p'            file   # last line, like tail -1
sed -n '5q;p'          file   # first 4 lines, like head -4, no SIGPIPE
sed -n '/re/p'         file   # like grep
sed -n '/re/!p'        file   # like grep -v
sed -n '/re/Ip'        file   # like grep -i
sed -n '/re/{p;q;}'    file   # first match only, then stop reading
sed -n '$='            file   # line count, like wc -l
sed -n '/re/='         file   # line numbers of matches
sed -n '/^.\{65\}/p'   file   # lines longer than 64 characters
sed -n 'n;n;p'         file   # every third line, portable
gsed -n '0~3p'         file   # every third line. GNU only

sed -n '5q;p' beats head -4 inside a pipeline that must not die early, and sed -n '500000,500010p;500011q' reads a slice of a huge file without scanning the rest.

Deleting

sed '5d'              file   # drop line 5
sed '2,4d'            file   # drop a range
sed '$d'              file   # drop the last line
sed '1,2d'            file   # skip a two-line header
sed '/^$/d'           file   # drop every blank line
sed '/^[[:space:]]*$/d' file # drop whitespace-only lines too
sed '/^#/d;/^$/d'     file   # strip comments and blanks from a config
sed '/re/,$d'         file   # from the first match to end of file
sed '/^begin$/,/^end$/d' file  # drop a marked block
sed '/^$/{N;/^\n$/D;}' file  # squeeze runs of blanks down to one

- d starts the next cycle immediately, so nothing after it in the script runs. - The blank-squeeze needs the ; before } to work on BSD sed. See the addresses topic for why.

Substituting

sed 's/old/new/'        file   # first match on each line
sed 's/old/new/g'       file   # every match
sed 's/x/Y/3'           file   # the third match only
gsed 's/x/Y/3g'         file   # third match onward. GNU only, BSD errors
sed 's/[[:space:]]\{1,\}/ /g'  file   # collapse runs of whitespace
sed 's/^/> /'           file   # quote a mail reply
sed 's/$/;/'            file   # append to every line
sed 's|/usr/local|/opt|g' file # alternate delimiter, no escaping needed
sed 's/<[^>]*>//g'      file   # crude tag stripper
sed 's/\(.*\)\//\1|/'   file   # change the LAST slash, thanks to greedy .*
sed '5!s/a/b/'          file   # everywhere except line 5
sed '/^#/!s/a/b/'       file   # skip comment lines

The greedy trick is the standard way to reach the last occurrence. .* grabs as much as it can, so the / that follows it is the final one on the line.

Whitespace and line endings

sed 's/^[[:space:]]*//'              file   # trim leading
sed 's/[[:space:]]*$//'              file   # trim trailing
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' file   # trim both
sed 's/\r$//'                        file   # CRLF to LF, dos2unix
sed 's/$/\r/'                        file   # LF to CRLF, unix2dos
sed -n '/\r$/l'                      file   # find the CR-terminated lines
sed 's/\t/    /g'                    file   # tabs to four spaces
sed 's/  */\t/g'                     file   # spaces to tabs

\t and \n work in patterns on both macOS sed and GNU sed, but they are not POSIX, so busybox and older systems may take them literally. The safe form is a real tab, which you get in a shell with $'\t' or by pressing ctrl-v then tab.

sed "s/$(printf '\t')/    /g" file   # portable tabs to spaces
sed $'s/\t/    /g'            file   # bash and zsh, also portable to BSD sed

Reversing, numbering, joining

sed '1!G;h;$!d'    file   # reverse the file, like tac
sed -n '1!G;h;$p'  file   # same thing, shorter to read
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'   # reverse each line, like rev
sed = file | sed 'N;s/\n/\t/'      # number lines, like cat -n
sed G             file   # double-space
sed 'n;d'         file   # undo double-spacing
sed -e :a -e '$q;N;3,$D;ba' file   # last 2 lines, like tail -2
sed -e :a -e 'N;$!ba' -e 's/\n/,/g' file   # join all lines with commas
sed '$!N;s/\n/ /'  file   # join lines in pairs
sed '$!N; /^\(.*\)\n\1$/!P; D'  file   # like uniq

The tac trick works because G appends the hold space to the pattern space and h copies it back, so the hold space accumulates the file in reverse. $!d suppresses everything until the last line.

Blocks and paragraphs

sed -n '/BEGIN/,/END/p'          file   # the block, markers included
sed -n '/BEGIN/,/END/{//!p;}'    file   # the block, markers excluded
sed '/BEGIN/,/END/d'             file   # everything but the block
sed -n '/re/{=;p;}' file | sed 'N;s/\n/:/'   # like grep -n

# print every blank-line-separated paragraph that contains foo
sed -e '/./{H;$!d;}' -e 'x;/foo/!d' file

# reflow each paragraph onto one line
sed -e '/./{H;$!d;}' -e 'x;s/\n/ /g;s/^ //;p' -e d file

- // reuses the last regex, which is how the marker-excluding form stays short. - The paragraph idioms emit a leading blank line, because the hold space starts out holding a newline. Pipe through sed '1{/^$/d;}' if that matters.

Insert, append, and quit

sed $'1i\\\nHEADER'  file   # prepend a line, bash or zsh
sed $'$a\\\nFOOTER'  file   # append a line
sed $'/^\\[main\\]$/a\\\nkey = value'  config   # add under a section
gsed '1i HEADER'     file   # GNU only one-line form
sed '1r header.txt'  file   # splice a file in after line 1
sed '$r footer.txt'  file   # splice a file in at the end
sed '10q'            file   # stop after 10 lines
sed '/^done$/q'      file   # stop at a sentinel
gsed '/error/q1'     file   # exit 1 if a match was seen. GNU only

Which of these are not portable

One-linerStatus
s/x/Y/Ng with a number and gGNU only, BSD refuses both flags
0~3p, 1~2d step addressesGNU only
\+ \? \w in a patternGNU, or BSD with -H. Plain BSD takes them literally
\s in a patternGNU only, use [[:space:]]
l N wrap widthGNU only, BSD l takes no argument
1i TEXT on one lineGNU only, POSIX needs a backslash newline
q1 exit code, Q, T, W, z, FGNU only. BSD also exits 1, but on a parse error, so $? lies
-i with no argumentGNU only, BSD needs -i ''
:a;p;ba labels joined by ;GNU only, BSD reads a;p;ba as the label
{cmd} with no ; before }GNU only, BSD wants {cmd;}

Everything else on this page was checked byte for byte against macOS sed and GNU sed 4.10, and behaves identically on both. A minimal sed such as busybox was not tested, and the \t caveat above is the one spot to watch there. When a script has to be portable and readable at once, write one -e per command and stop fighting the quoting.