sed is the stream editor. It reads a file (or piped input) line by line, applies transformations you specify, and writes the result to standard output. It's like running a tiny find-and-replace through your file from the command line, without ever opening an editor.
You'll see sed most often in three contexts: quick text substitutions, scripted edits to config files, and the occasional log-munging pipeline. This guide covers exactly that.
The classic: substitute
sed 's/old/new/' file.txt
Reads file.txt, replaces the first occurrence of "old" with "new" on each line, prints the result. Doesn't change the original file.
The s command structure is s/pattern/replacement/flags. Common flags:
g— replace all occurrences on each line, not just the firsti— case-insensitive match3— replace only the third match on each line
sed 's/old/new/g' file.txt # all occurrences per line
sed 's/CAT/dog/gi' file.txt # any case of "cat" → "dog"
Edit a file in place (-i)
To modify the file directly instead of just printing:
sed -i 's/old/new/g' file.txt # Linux (GNU sed)
sed -i '' 's/old/new/g' file.txt # BSD / macOS — empty backup suffix
sed -i.bak 's/old/new/g' file.txt # keep a backup as file.txt.bak
Heads up: the -i flag is one of the few places sed differs between GNU (Linux) and BSD (FreeBSD/macOS). On BSD you must give it an argument — an empty string '' means "no backup."
Different separator (when your text contains slashes)
The first character after s is the separator. Use any character that's not in your strings:
# classic problem: paths contain slashes
sed 's|/usr/local/|/opt/|g' config.txt
sed 's#http://#https://#' urls.txt
Delete lines
sed '/pattern/d' file.txt # delete lines matching pattern
sed '/^$/d' file.txt # delete blank lines
sed '/^#/d' file.txt # delete comment lines
sed '1d' file.txt # delete the first line (e.g., CSV header)
sed '$d' file.txt # delete the last line
sed '1,10d' file.txt # delete lines 1 to 10
Print only matching lines (-n + /p)
By default sed prints every line. The -n flag silences that, then you tell it explicitly what to print:
# works like grep
sed -n '/error/p' /var/log/syslog
# print only lines 10–20
sed -n '10,20p' file.txt
# print from line 10 to the end of the file ($ = the last line)
sed -n '10,$p' file.txt
Address ranges — work on a slice of the file
Most commands accept an "address" telling sed which lines to act on:
sed '1,5s/foo/bar/g' file.txt # only on lines 1–5
sed '/BEGIN/,/END/s/foo/bar/g' file.txt # between the BEGIN and END markers
sed '10,$d' file.txt # delete from line 10 to the end
This is one of sed's superpowers — you can scope an edit precisely. The pattern /BEGIN/,/END/ is especially handy for editing config blocks bounded by markers.
Multiple commands in one pass
Use -e or a semicolon:
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
sed 's/foo/bar/g; s/baz/qux/g' file.txt
For more complex edits, write a sed script file:
# tidy.sed
/^#/d
/^$/d
s/[[:space:]]\+$//
s/[[:space:]]\+/ /g
Run it with:
sed -f tidy.sed input.txt
That tiny script strips comments, blank lines, trailing whitespace, and collapses runs of internal whitespace — useful for cleaning up someone else's config file.
Capture groups for restructuring
Use \1, \2, etc. in the replacement to refer back to parts of the match. The pattern uses \( ... \) to capture (or ( ... ) with the -E flag for extended regex):
# swap the order of "first last" to "last, first"
echo "Ada Lovelace" | sed -E 's/(\S+) (\S+)/\2, \1/'
# Lovelace, Ada
# capture a port out of a URL
echo "http://example.com:8080/path" | sed -E 's|.*:([0-9]+)/.*|\1|'
# 8080
Real-world examples
# strip Windows-style carriage returns from a file
sed -i 's/\r$//' file.txt
# uncomment a setting in a config file
sed -i 's/^#\(Port .*\)/\1/' /etc/ssh/sshd_config
# change a value in a config file
sudo sed -i 's/^Port .*/Port 2222/' /etc/ssh/sshd_config
# extract just the lines between two markers
sed -n '/^BEGIN/,/^END/p' config.txt
# add a line after every match
sed '/^Section/a\
new line here' file.txt
The shortest summary
sed 's/old/new/g'— replace all "old" with "new" on every line.-i— edit the file in place.-i.bakto keep a backup./pattern/d— delete matching lines.-n '/pattern/p'— print only matching lines (sed as grep).- Address ranges like
1,10or/BEGIN/,/END/scope edits. - Combine multiple edits with
-eor a script file.
Combined with awk and the basic pipe vocabulary, you'll handle the great majority of "I need to transform a text file" tasks without ever writing a real program.