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

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
SSH keys and secure file copy

Discussion

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

Related Posts