Editing Text with sed
Prerequisites: Searching text with grep
sed (stream editor) transforms text line by line. Its most common job
is find and replace.
Substitution
echo "I love cats. cats are great." | sed 's/cats/dogs/'
echo "I love cats. cats are great." | sed 's/cats/dogs/g'
echo "Hello World" | sed 's/world/there/I'
I love dogs. cats are great.
I love dogs. dogs are great.
Hello there
s/old/new/ replaces the first match on each line; the g flag replaces
all matches; I ignores case (GNU sed).
Editing files
cat > config.ini <<'EOF'
host=localhost
port=8080
debug=true
EOF
sed 's/port=8080/port=9090/' config.ini
echo "--- file unchanged:"
cat config.ini
sed -i.bak 's/debug=true/debug=false/' config.ini
echo "--- after sed -i:"
cat config.ini
ls config.ini*
host=localhost
port=9090
debug=true
--- file unchanged:
host=localhost
port=8080
debug=true
--- after sed -i:
host=localhost
port=8080
debug=false
config.ini
config.ini.bak
- By default,
sedprints the result and leaves the file alone. -iedits the file in place.-i.bakkeeps a backup first — a good habit. (On macOS's BSDsed,-irequires an argument:-i ''for no backup.)
Selecting lines
printf 'line %s\n' 1 2 3 4 5 > nums.txt
sed -n '2,4p' nums.txt
echo "---"
sed '1d' nums.txt
echo "---"
sed '/3/d' nums.txt
line 2
line 3
line 4
---
line 2
line 3
line 4
line 5
---
line 1
line 2
line 4
line 5
-n '2,4p'prints only lines 2 to 4.1ddeletes line 1 (handy for skipping a CSV header)./pattern/ddeletes lines matching a pattern.
Capture groups
echo "2025-04-22" | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'
echo "Ada Lovelace" | sed -E 's/(\w+) (\w+)/\2, \1/'
22/04/2025
Lovelace, Ada
-E enables extended regex; ( ) captures parts, and \1, \2, \3
insert them in the replacement.
Common mistakes
- Slashes in the text: replacing paths with
s/\/usr\/local/...gets unreadable. Use a different delimiter:s#/usr/local#/opt#. - Running
sed -iwithout testing the expression first. Run it without-i, check the output, then add-i.