Skip to content
Go back

Sed 101

· Updated:
By SumGuy 5 min read
Sed 101

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:

Terminal window
sed 's/find/replace/' filename.txt

That’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

Without g: only first match
sed 's/dog/cat/' pets.txt

If your line is “I have a dog and my dog has fleas,” only the first “dog” becomes “cat.”

With g: global, all matches
sed 's/dog/cat/g' pets.txt

Now both “dog”s become “cat”s. Use g by default — you almost always want it.

The i flag — case-insensitive

Terminal window
sed 's/Docker/podman/i' config.yaml

Matches “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:

Terminal window
sed -n 's/error/ERROR/p' app.log

Only prints lines that had the substitution.

Multiple expressions with -e

Want to chain multiple replacements?

Two replacements in one command
sed -e 's/cats/sloths/g' -e 's/dogs/ducks/g' animals.txt

Each -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

Terminal window
sed '5s/old/new/g' file.txt

Replace only on line 5.

Line ranges

Terminal window
sed '2,7s/old/new/g' file.txt

Replace on lines 2 through 7.

Pattern matching

Terminal window
sed '/^DEBUG/s/old/new/g' app.log

Replace only on lines starting with “DEBUG”.

Terminal window
sed '/start/,/end/s/old/new/g' file.txt

Replace 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:

Delete lines matching a pattern
sed '/^#/d' config.conf

Delete all comment lines (starting with #).

Delete line ranges
sed '10,20d' file.txt

Delete lines 10–20.

Printing specific lines (the p command with -n)

Terminal window
sed -n '5,10p' file.txt

Print 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:

Terminal window
sed -i 's/old/new/g' file.txt

But here’s the gotcha: macOS’s BSD sed is different from GNU sed. On macOS, you must provide a backup extension:

macOS: requires -i '' for no backup
sed -i '' 's/old/new/g' file.txt

Without the empty string, BSD sed treats the script argument as the backup extension and the filename as the command, causing an error. Forget this once and you’ll be searching StackOverflow forever. Write it into your muscle memory now.

To be safe across systems, always use:

Terminal window
sed -i.bak 's/old/new/g' file.txt

Creates 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:

Using ; as delimiter instead of /
sed 's;/home/kingpin;/home/notkingpin;g' paths.txt

Or use any other character that’s unlikely to appear in your data (;, |, #, @).

Real-world use cases

Strip comments from a config:

Terminal window
sed '/^#/d' nginx.conf | sed '/^$/d'

Delete comment lines AND blank lines. Pipe it to tee to overwrite in place:

Terminal window
sed -i '/^#/d; /^$/d' nginx.conf

Fix Windows line endings (CRLF to LF):

Terminal window
sed -i 's/\r$//' filename.txt

Extract and clean up log lines:

Terminal window
sed -n '/ERROR/p' app.log | sed 's/ERROR:/[!]/g'

Bulk rename variables in code:

Terminal window
sed -i 's/\bOLD_VAR\b/NEW_VAR/g' *.py

The \b is a word boundary — matches “OLD_VAR” but not “OLD_VAR_SUFFIX”.

Quick cheatsheet

PatternWhat it does
sed 's/find/replace/' fileReplace first on each line
sed 's/find/replace/g' fileReplace all on each line
sed 's/find/replace/i' fileCase-insensitive
sed '5s/find/replace/' fileLine 5 only
sed '2,7s/find/replace/g' fileLines 2–7
sed '/pattern/s/find/replace/g' fileLines matching pattern
sed '/start/,/end/s/find/replace/g' fileBetween patterns
sed '/pattern/d' fileDelete matching lines
sed -n '5,10p' filePrint lines 5–10
sed -i.bak 's/find/replace/g' fileIn-place with backup
sed -e 's/a/b/g' -e 's/c/d/g' fileMultiple 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.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
When systemd swallows your service logs
Next Post
Why You Should Switch to ZShell (zsh)

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts