skip to content

sed β€” Stream Editor

Non-interactive text transformation. Substitution, deletion, insertion, address ranges, in-place editing, and multi-line patterns with practical recipes.

5 min read 14 snippets 2d ago intermediate

sed β€” Stream Editor#

Syntax#

sed [OPTIONS] 'SCRIPT' [FILE...]
sed [OPTIONS] -e 'CMD' -e 'CMD' [FILE...]
sed [OPTIONS] -f script.sed [FILE...]

Common options#

OptionMeaning
-nSuppress auto-print (only explicit p prints)
-eAdd an expression
-fRead script from file
-iIn-place edit (GNU: -i'' or -i suffix)
-E / -rExtended regex (no \+, | escaping)
-zNUL-delimited input (for multi-line via NUL)

Address forms#

Addresses select which lines a command applies to.

AddressMeaning
NLine N
$Last line
N,MLines N through M
N~SEvery S-th line starting from N
/regex/Lines matching regex
/re1/,/re2/From re1-match through re2-match
! suffixNegate the address
0,/re/GNU: from line 0 (first match even on line 1)
sed '5d'           file   # delete line 5
sed '2,4d'         file   # delete lines 2–4
sed '$d'           file   # delete last line
sed '/^#/d'        file   # delete comment lines
sed '1~2d'         file   # delete odd lines (1,3,5,…)
sed '/START/,/END/d' file  # delete range (inclusive)

Substitution β€” s#

s/REGEX/REPLACEMENT/FLAGS
FlagMeaning
gReplace all occurrences on the line
NReplace only the N-th occurrence
iCase-insensitive (GNU)
pPrint line if substitution made
w fileWrite line to file if substitution made
sed 's/foo/bar/'           file   # first occurrence per line
sed 's/foo/bar/g'          file   # all occurrences
sed 's/foo/bar/2'          file   # second occurrence only
sed 's/foo/bar/ig'         file   # case-insensitive, all
sed -n 's/error/ERROR/p'   file   # print only changed lines

Regex in substitutions#

# Capture groups: \1 \2 ... (BRE) or \1 with -E
sed 's/\(first\) \(last\)/\2 \1/'       file   # swap words (BRE)
sed -E 's/(first) (last)/\2 \1/'        file   # same, ERE
sed -E 's/([0-9]+)/[\1]/g'             file   # wrap numbers in []
sed 's/.*/  &/'                          file   # indent every line

# & represents the entire match
sed 's/[A-Z][a-z]*/[&]/g'  file   # wrap each capitalized word

# Alternate delimiters (useful for paths)
sed 's|/usr/local|/opt|g'   file
sed 's,/home/alice,/home/bob,g'  file

Delete β€” d#

sed '/^$/d'            file   # delete empty lines
sed '/^\s*$/d'         file   # delete blank/whitespace-only lines
sed '/^#/d'            file   # delete comment lines
sed '1d'               file   # delete first line (skip header)
sed -n '5,10p'         file   # print lines 5–10 (like head/tail)
sed -n '/ERROR/p'      file   # print matching lines (like grep)
sed -n '$p'            file   # print last line
sed -n '1p'            file   # print first line

Insert, append, change β€” i, a, c#

sed '1i\# Header comment'    file   # insert before line 1
sed '$a\# Footer'            file   # append after last line
sed '/^Host /a\  StrictHostKeyChecking no'  ssh_config  # append after match

sed '5c\REPLACED LINE'       file   # change (replace) line 5
sed '/old text/c\new text'   file   # change matching line

Read/write files β€” r, w#

sed '/INSERT_HERE/r extra.txt'  template   # splice file contents
sed -n '/ERROR/w errors.txt'   app.log     # write matches to file

Quit β€” q, Q#

sed '10q'   file   # print first 10 lines then quit (like head -10)
sed '/DONE/q' file # quit after first matching line
sed '0,/START/d; /END/q'  file  # print lines between START and END

In-place editing#

# GNU sed
sed -i 's/foo/bar/g' file.txt          # in-place, no backup
sed -i.bak 's/foo/bar/g' file.txt      # in-place with .bak backup

# macOS (BSD sed requires explicit suffix even for no-backup)
sed -i '' 's/foo/bar/g' file.txt

# Multiple files
sed -i 's/oldhost/newhost/g' *.conf
find . -name "*.py" -exec sed -i 's/python2/python3/g' {} +

Multiple expressions#

sed -e 's/foo/bar/g' -e '/^#/d' -e 's/baz/qux/' file

# Or a semicolon-separated script
sed 's/foo/bar/g; /^#/d; s/baz/qux/' file

Hold space (advanced)#

The hold space is a secondary buffer. Commands: h (copy pattern→hold), H (append), g (copy hold→pattern), G (append), x (exchange).

# Reverse line order of a file
sed -n '1!G; h; $p' file

# Print the line before a match
sed -n '/error/{x;p;d}; h' file

# Delete duplicate consecutive lines (like uniq)
sed '$!N; /^\(.*\)\n\1$/!P; D' file

Practical recipes#

# Remove trailing whitespace
sed 's/[[:space:]]*$//' file

# Trim leading whitespace
sed 's/^[[:space:]]*//' file

# Remove blank lines
sed '/^[[:space:]]*$/d' file

# Convert Windows CRLF to LF
sed 's/\r$//' file

# Extract lines between two patterns (exclusive)
sed -n '/BEGIN/{n; /END/!{p; b}; b}; /BEGIN/,/END/{/BEGIN/d; /END/d; p}' file

# Simpler exclusive range
sed -n '/START/,/END/{/START/d;/END/d;p}' file

# Number non-empty lines
sed '/./=' file | sed 'N; s/\n/ /'

# Double-space a file
sed 'G' file

# Extract value from key=value config
sed -n 's/^database_host=//p' config.ini

# Comment out lines matching a pattern
sed '/^ServerName/s/^/# /' httpd.conf

# Uncomment lines matching a pattern
sed '/^# ServerName/s/^# //' httpd.conf

[!TIP] For complex, multi-field transformations, awk is usually clearer than sed. Use sed for line-oriented substitutions and deletions; switch to awk when you need to reference fields or do arithmetic.

[!WARN] The in-place behaviour differs between GNU sed (-i suffix optional) and BSD/macOS sed (-i '' required). For portable scripts, write to a temp file and mv instead of using -i.