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:
sed [OPTIONS] 'SCRIPT' FILE
Create this tiny practice file so every example below is reproducible:
printf 'apple 10\nbanana 20\ncherry 30\napple 40\n' > fruits.txt
# fruits.txt now contains:
apple 10
banana 20
cherry 30
apple 40
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.Basic Replace
Replace the first match of a pattern on each line.
sed 's/apple/APPLE/' fruits.txt
APPLE 10 banana 20 cherry 30 APPLE 40
g flag below.Global & Case-Insensitive
The g flag replaces every match on a line; I makes matching case-insensitive.
# Replace every 'a' with 'X'
sed 's/a/X/g' fruits.txt
sed 's/apple/APPLE/gI' fruits.txt
# s/a/X/g output:
Xpple 10
bXnXnX 20
cherry 30
Xpple 40
Nth Occurrence / From Nth
A number flag targets a specific occurrence; combine with g to change from the Nth onward.
echo 'oo oo oo' | sed 's/o/0/2'
o0 oo oo
echo 'oo oo oo' | sed 's/o/0/3g'
# from the 3rd 'o' onward, every 'o' becomes '0'
oo 00 00
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.
sed '/banana/ s/20/99/' fruits.txt
sed '2 s/banana/BANANA/' fruits.txt
sed '2,3 s/[0-9]*/NUM/' fruits.txt
# /banana/ s/20/99/ output: apple 10 banana 99 cherry 30 apple 40
Alternate Delimiter for Paths
When the text contains slashes, pick a different delimiter so you do not have to escape every /.
echo /usr/local/bin | sed 's#/usr/local#/opt#'
/opt/bin
s becomes the delimiter — any char works: s#..#..#, s|..|..|, s,..,..,. Very handy when your pattern or replacement contains /.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.
sed -i 's/apple/APPLE/g' fruits.txt
# Saves original as fruits.txt.bak before editing
sed -i.bak 's/apple/APPLE/g' fruits.txt
-i rewrites the file immediately. Always run the command without -i first to eyeball the output, or use -i.bak so you can restore.-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.Delete by Line / Range / Last
The d command deletes whole lines matched by its address.
sed '2d' fruits.txt
sed '2,4d' fruits.txt
sed '$d' fruits.txt
# '2d' output:
apple 10
cherry 30
apple 40
Delete by Pattern & Blanks
Delete lines matching a regex — great for stripping blank lines and comments from config files.
sed '/banana/d' fruits.txt
sed '/^$/d' fruits.txt
sed '/^#/d' fruits.txt
!: sed '/apple/!d' fruits.txt deletes everything except lines matching apple.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.
sed -n '3p' fruits.txt
sed -n '2,4p' fruits.txt
sed -n '$p' fruits.txt sed -n '1,5p' fruits.txt
# '3p' output:
cherry 30
Print by Pattern & Between Patterns
Print only matching lines (like grep), or everything between two patterns.
sed -n '/apple/p' fruits.txt
sed -n '/apple/,/cherry/p' fruits.txt
# /apple/,/cherry/p output:
apple 10
banana 20
cherry 30
i (insert), a (append), c (change)
i adds a line before the address, a adds one after, and c replaces the whole matched line.
sed '2i\INSERTED BEFORE LINE 2' fruits.txt
sed '2a\APPENDED AFTER LINE 2' fruits.txt
sed '2c\REPLACED LINE 2' fruits.txt
sed '/banana/a\--- note ---' fruits.txt
# '/banana/a\--- note ---' output: apple 10 banana 20 --- note --- cherry 30 apple 40
Capture Groups & &
Parentheses capture parts of the match; recall them with \1, \2, ... The & stands for the entire match.
# -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
# Basic regex: \+ is "one or more"; & = whole match
sed 's/[0-9]\+/[&]/' fruits.txt
apple [10] banana [20] cherry [30] apple [40]
\(...\). Add -E for extended regex where (...) and + work unescaped.Anchors & Character Classes
Common line-shaping one-liners using ^ (start), $ (end), and classes like [0-9].
sed 's/^/> /' fruits.txt
sed 's/ *$//' fruits.txt
sed 's/[0-9]//g' fruits.txt
# 's/^/> /' output: > apple 10 > banana 20 > cherry 30 > apple 40
Run Multiple Edits at Once
Chain edits with repeated -e, with semicolons, or group commands under one address with { }.
sed -e 's/apple/APPLE/' -e 's/banana/BANANA/' fruits.txt
sed 's/apple/APPLE/; s/30/99/' fruits.txt
# 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
Common Pitfalls
The three things that trip up almost everyone using sed.
# 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
# Editing paths? Switch the / delimiter to # or |
echo /etc/nginx/nginx.conf | sed 's#/etc/nginx#/opt/nginx#'
sed -i 's/a/A/' file # GNU / Linux sed -i '' 's/a/A/' file # macOS / BSD (needs empty backup arg)
-i first, eyeball the printed output, and only then add -i (or -i.bak) once you are happy with it.