What the hell is sed and why should you care?
sed is the stream editor — it’s a command-line tool that reads text one line at a time, applies transformations based on patterns you give it, and spits out the result. Think of it as a scalpel for text files: surgical precision, no fluff.
Here’s the thing: if you’re doing anything with configuration files, logs, or bulk text changes, sed will save you hours of manual editing. It’s been around since the 1970s for a reason. Your future self at 2 AM will appreciate not having to open a file in vim and search-replace 500 times.
The basic syntax (that 90% of your usage falls into)
The bread and butter of sed is the s command (substitute). Here’s the shape of it:
sed 's/find/replace/' filename.txtThat’s it. Replace the first occurrence of “find” with “replace” on each line. But there’s more power hiding in those flags.
Flags that actually matter
The g flag — replace ALL occurrences on a line
sed 's/dog/cat/' pets.txtIf your line is “I have a dog and my dog has fleas,” only the first “dog” becomes “cat.”
sed 's/dog/cat/g' pets.txtNow both “dog”s become “cat”s. Use g by default — you almost always want it.
The i flag — case-insensitive
sed 's/Docker/podman/i' config.yamlMatches “docker”, “Docker”, “DOCKER”, and replaces with lowercase “podman” (the pattern is literal, only the match is case-insensitive).
The n flag — silent mode (print only matches)
By default, sed prints every line. The n flag suppresses automatic output, and p prints only lines that match. Useful for filtering:
sed -n 's/error/ERROR/p' app.logOnly prints lines that had the substitution.
Multiple expressions with -e
Want to chain multiple replacements?
sed -e 's/cats/sloths/g' -e 's/dogs/ducks/g' animals.txtEach -e is applied in order. This is cleaner than piping sed to sed (which works, but is inelegant).
Line addressing — replace only where you want
Specific line numbers
sed '5s/old/new/g' file.txtReplace only on line 5.
Line ranges
sed '2,7s/old/new/g' file.txtReplace on lines 2 through 7.
Pattern matching
sed '/^DEBUG/s/old/new/g' app.logReplace only on lines starting with “DEBUG”.
sed '/start/,/end/s/old/new/g' file.txtReplace between the first line matching “start” and the first line matching “end” (inclusive).
Deleting lines (the d command)
Sometimes you want to remove lines entirely:
sed '/^#/d' config.confDelete all comment lines (starting with #).
sed '10,20d' file.txtDelete lines 10–20.
Printing specific lines (the p command with -n)
sed -n '5,10p' file.txtPrint only lines 5–10 (like head -n 10 | tail -n 6, but shorter).
In-place editing with -i (the dangerous one)
By default, sed outputs to stdout. To actually overwrite the file:
sed -i 's/old/new/g' file.txtBut here’s the gotcha: macOS’s BSD sed is different from GNU sed. On macOS, you must provide a backup extension:
sed -i '' 's/old/new/g' file.txtWithout the empty string, it’ll create a .bak file. Forget this once and you’ll be searching StackOverflow forever. Write it into your muscle memory now.
To be safe across systems, always use:
sed -i.bak 's/old/new/g' file.txtCreates a .bak backup on all platforms, which you can delete later (or keep, your call).
Dealing with special characters (the / problem)
If your find/replace contains slashes (like file paths), change the delimiter:
sed 's;/home/kingpin;/home/notkingpin;g' paths.txtOr use any other character that’s unlikely to appear in your data (;, |, #, @).
Real-world use cases
Strip comments from a config:
sed '/^#/d' nginx.conf | sed '/^$/d'Delete comment lines AND blank lines. Pipe it to tee to overwrite in place:
sed -i '/^#/d; /^$/d' nginx.confFix Windows line endings (CRLF to LF):
sed -i 's/\r$//' filename.txtExtract and clean up log lines:
sed -n '/ERROR/p' app.log | sed 's/ERROR:/[!]/g'Bulk rename variables in code:
sed -i 's/\bOLD_VAR\b/NEW_VAR/g' *.pyThe \b is a word boundary — matches “OLD_VAR” but not “OLD_VAR_SUFFIX”.
Quick cheatsheet
| Pattern | What it does |
|---|---|
sed 's/find/replace/' file | Replace first on each line |
sed 's/find/replace/g' file | Replace all on each line |
sed 's/find/replace/i' file | Case-insensitive |
sed '5s/find/replace/' file | Line 5 only |
sed '2,7s/find/replace/g' file | Lines 2–7 |
sed '/pattern/s/find/replace/g' file | Lines matching pattern |
sed '/start/,/end/s/find/replace/g' file | Between patterns |
sed '/pattern/d' file | Delete matching lines |
sed -n '5,10p' file | Print lines 5–10 |
sed -i.bak 's/find/replace/g' file | In-place with backup |
sed -e 's/a/b/g' -e 's/c/d/g' file | Multiple expressions |
That’s it. You now know enough sed to handle 95% of real-world situations. The man page is a rabbit hole of obscure features — you don’t need them yet. Start with s/find/replace/g, and level up only when you hit a wall.
Your config files (and your 2 AM self) will thank you.