← Back
📖 What is sed?
📖

The Stream Editor in a Nutshell

sed reads its input one line at a time, applies your editing script to each line, and prints the result to standard output. It never touches the original file unless you pass -i, so it is safe to experiment with. The general form is:

Basic form
sed [OPTIONS] 'SCRIPT' FILE

Create this tiny practice file so every example below is reproducible:

bash — Make fruits.txt
printf 'apple 10\nbanana 20\ncherry 30\napple 40\n' > fruits.txt
# fruits.txt now contains:
apple 10
banana 20
cherry 30
apple 40
💡
All examples below operate on fruits.txt, and a few read from stdin using echo ... | sed. Since sed only prints to the screen, run them freely — your file stays untouched until you add -i.
🔁 Substitution (s///)
1

Basic Replace

Replace the first match of a pattern on each line.

bash
sed 's/apple/APPLE/' fruits.txt
APPLE 10
banana 20
cherry 30
APPLE 40
💡
Only the first occurrence per line is changed. To change all of them, see the g flag below.
2

Global & Case-Insensitive

The g flag replaces every match on a line; I makes matching case-insensitive.

bash — g: replace all on line
# Replace every 'a' with 'X'
sed 's/a/X/g' fruits.txt
bash — gI: all, ignore case
sed 's/apple/APPLE/gI' fruits.txt
# s/a/X/g output:
Xpple 10
bXnXnX 20
cherry 30
Xpple 40
3

Nth Occurrence / From Nth

A number flag targets a specific occurrence; combine with g to change from the Nth onward.

bash — 2nd occurrence only
echo 'oo oo oo' | sed 's/o/0/2'
o0 oo oo
bash — 3rd occurrence onward
echo 'oo oo oo' | sed 's/o/0/3g'
# from the 3rd 'o' onward, every 'o' becomes '0'
oo 00 00
4

Only on Matching / Specific Lines

Prefix the s command with an address (a pattern, a line number, or a range) to restrict where it runs.

bash — only lines matching /banana/
sed '/banana/ s/20/99/' fruits.txt
bash — only line 2
sed '2 s/banana/BANANA/' fruits.txt
bash — lines 2 through 3
sed '2,3 s/[0-9]*/NUM/' fruits.txt
# /banana/ s/20/99/ output:
apple 10
banana 99
cherry 30
apple 40
5

Alternate Delimiter for Paths

When the text contains slashes, pick a different delimiter so you do not have to escape every /.

bash
echo /usr/local/bin | sed 's#/usr/local#/opt#'
/opt/bin
💡
The character right after s becomes the delimiter — any char works: s#..#..#, s|..|..|, s,..,..,. Very handy when your pattern or replacement contains /.
✏️ In-place Editing (-i)
6

Edit a File in Place

The -i option writes changes back to the file instead of printing them. Add a suffix to keep a backup.

bash — modify file directly
sed -i 's/apple/APPLE/g' fruits.txt
bash — with a .bak backup
# Saves original as fruits.txt.bak before editing
sed -i.bak 's/apple/APPLE/g' fruits.txt
⚠️
No undo! -i rewrites the file immediately. Always run the command without -i first to eyeball the output, or use -i.bak so you can restore.
💡
macOS / BSD sed differs: there -i requires an explicit backup argument, so use sed -i '' 's/.../.../' file (empty string = no backup). GNU sed on Linux uses -i with no argument.
🗑️ Deleting Lines (d)
7

Delete by Line / Range / Last

The d command deletes whole lines matched by its address.

bash — delete line 2
sed '2d' fruits.txt
bash — delete lines 2 to 4
sed '2,4d' fruits.txt
bash — delete the last line
sed '$d' fruits.txt
# '2d' output:
apple 10
cherry 30
apple 40
8

Delete by Pattern & Blanks

Delete lines matching a regex — great for stripping blank lines and comments from config files.

bash — delete matching lines
sed '/banana/d' fruits.txt
bash — delete blank lines
sed '/^$/d' fruits.txt
bash — delete comment lines
sed '/^#/d' fruits.txt
💡
Negate an address with !: sed '/apple/!d' fruits.txt deletes everything except lines matching apple.
🖨️ Printing Lines (-n + p)
9

Print Specific Lines

-n suppresses sed's automatic printing, so only lines you explicitly print appear — a handy stand-in for head or line-slicing.

bash — print line 3
sed -n '3p' fruits.txt
bash — print a range
sed -n '2,4p' fruits.txt
bash — last line / like head -5
sed -n '$p' fruits.txt
sed -n '1,5p' fruits.txt
# '3p' output:
cherry 30
10

Print by Pattern & Between Patterns

Print only matching lines (like grep), or everything between two patterns.

bash — lines matching /apple/
sed -n '/apple/p' fruits.txt
bash — from first match to next
sed -n '/apple/,/cherry/p' fruits.txt
# /apple/,/cherry/p output:
apple 10
banana 20
cherry 30
➕ Insert / Append / Change
11

i (insert), a (append), c (change)

i adds a line before the address, a adds one after, and c replaces the whole matched line.

bash — insert before line 2
sed '2i\INSERTED BEFORE LINE 2' fruits.txt
bash — append after line 2
sed '2a\APPENDED AFTER LINE 2' fruits.txt
bash — change line 2
sed '2c\REPLACED LINE 2' fruits.txt
bash — append after a pattern
sed '/banana/a\--- note ---' fruits.txt
# '/banana/a\--- note ---' output:
apple 10
banana 20
--- note ---
cherry 30
apple 40
🔎 Regex & Backreferences
12

Capture Groups & &

Parentheses capture parts of the match; recall them with \1, \2, ... The & stands for the entire match.

bash — swap word and number
# -E enables extended regex (unescaped parens)
sed -E 's/([a-z]+) ([0-9]+)/\2 \1/' fruits.txt
10 apple
20 banana
30 cherry
40 apple
bash — wrap the match with &
# Basic regex: \+ is "one or more"; & = whole match
sed 's/[0-9]\+/[&]/' fruits.txt
apple [10]
banana [20]
cherry [30]
apple [40]
💡
In basic regex (default) you must escape groups as \(...\). Add -E for extended regex where (...) and + work unescaped.
13

Anchors & Character Classes

Common line-shaping one-liners using ^ (start), $ (end), and classes like [0-9].

bash — prefix each line
sed 's/^/> /' fruits.txt
bash — strip trailing spaces
sed 's/ *$//' fruits.txt
bash — remove all digits
sed 's/[0-9]//g' fruits.txt
# 's/^/> /' output:
> apple 10
> banana 20
> cherry 30
> apple 40
🔗 Combining Commands
14

Run Multiple Edits at Once

Chain edits with repeated -e, with semicolons, or group commands under one address with { }.

bash — multiple -e scripts
sed -e 's/apple/APPLE/' -e 's/banana/BANANA/' fruits.txt
bash — semicolon-separated
sed 's/apple/APPLE/; s/30/99/' fruits.txt
bash — grouped under one address
# Both edits run only on lines matching /apple/
sed '/apple/{ s/10/11/; s/40/44/ }' fruits.txt
# '/apple/{ s/10/11/; s/40/44/ }' output:
apple 11
banana 20
cherry 30
apple 44
🚑 Gotchas & Best Practices
🔧

Common Pitfalls

The three things that trip up almost everyone using sed.

bash — quote your scripts
# Use SINGLE quotes so the shell doesn't expand $ or &
sed 's/ *$//' fruits.txt          # good
# Double quotes let the shell eat $ and & before sed sees them
bash — pick a safe delimiter
# Editing paths? Switch the / delimiter to # or |
echo /etc/nginx/nginx.conf | sed 's#/etc/nginx#/opt/nginx#'
bash — GNU vs BSD -i
sed -i    's/a/A/' file   # GNU / Linux
sed -i '' 's/a/A/' file   # macOS / BSD (needs empty backup arg)
Golden rule: build and test your script without -i first, eyeball the printed output, and only then add -i (or -i.bak) once you are happy with it.