Skip to content
Cheat Sheets 6 min read

sed Basics Cheatsheet (macOS / BSD sed)

I was troubleshooting some Nikto+Brew issues and realized how rarely I’ve used SED. Here’s a quick cheatsheet my bff Claude made me, specific to MacOS.

You’re on macOS, which ships **BSD sed**, not GNU sed. The single biggest gotcha:

in-place editing on BSD sed *requires* an argument after `-i` (even if empty), while GNU sed (Linux) treats a bare `-i` as in-place-no-backup.

# macOS/BSD — empty string required, as its own argument

sed -i '' 's/foo/bar/' file.txt

# Linux/GNU — no argument needed

sed -i 's/foo/bar/' file.txt

# Portable backup version (works on both) — creates file.txt.bak

sed -i.bak 's/foo/bar/' file.txt

If you ever move this workflow to a Linux VM/container, this is the line that’ll bite you.

Core syntax

sed ‘s/PATTERN/REPLACEMENT/FLAGS’ file.txt

– `s` = substitute

– Delimiter is usually `/` but can be anything (`|`, `#`, `,`) — useful when your pattern contains slashes (like file paths)

– Without `-i`, sed prints to stdout and leaves the file untouched — always safe to test with first

Everyday substitutions

# Replace first match per line ("old" is pattern in file.txt being replaced with "new")
sed 's/old/new/' file.txt

# Replace ALL matches per line (g = global)
sed 's/old/new/g' file.txt

# Replace only on the Nth occurrence in each line
sed 's/old/new/2' file.txt

# Case-insensitive match
sed 's/old/new/gi' file.txt

# In-place edit (macOS)
sed -i '' 's/old/new/g' file.txt

# Use a different delimiter to avoid escaping slashes (great for paths)
sed -i '' 's|/opt/homebrew/Cellar/nikto/2.1.6|/opt/homebrew/opt/nikto|' nikto.conf

Multiple replacements in one pass

# Chain with -e
sed -i '' -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt

# Order matters if one pattern is a substring of another —
# replace the MORE SPECIFIC (longer) pattern first

sed -i '' \
-e 's|/opt/homebrew/Cellar/nikto/2.1.6/share/nikto/docs|/opt/homebrew/opt/nikto/share/nikto/docs|' \
-e 's|/opt/homebrew/Cellar/nikto/2.1.6|/opt/homebrew/opt/nikto|' \
nikto.conf

Line-based edits (no pattern matching needed)

# Append text to the end of every line
sed 's/$/:443/' hosts.txt

# Prepend text to the start of every line
sed 's/^/https:\/\//' hosts.txt

# Delete blank lines
sed '/^$/d' file.txt

# Delete lines matching a pattern
sed '/^#/d' file.txt # strip comment lines
sed '/DEBUG/d' logfile.txt # strip lines containing DEBUG

# Print (or delete) only a line range
sed -n '10,20p' file.txt # print lines 10-20
sed '10,20d' file.txt # delete lines 10-20

Useful for recon / pentest workflows

# Strip protocol prefix from a list of URLs (leave bare hostnames)
sed -E 's|https?://||' urls.txt

# Extract just hostnames, dropping any path/query
sed -E 's|^(https?://[^/]+).*|\1|' urls.txt

# Turn a plain host list into host:port pairs
sed 's/$/:443/' scope.list

# Add a scheme back onto a bare host list
sed 's/^/https:\/\//' scope.list

# Comment out a line matching a pattern (instead of deleting it)
sed -i '' '/PLUGINDIR/s/^/#/' nikto.conf

# Remove trailing whitespace/CRLF from a file (common with copy-pasted lists)
sed -i '' 's/[[:space:]]*$//' scope.list
sed -i '' 's/\r$//' scope.list # strip Windows line endings specifically

Regex flavor notes (BSD sed)

– Basic regex by default — use `-E` (or `-r` on GNU) for extended regex so you

can use `+`, `?`, `|`, `()` without backslash-escaping them

– Capture groups: `\(…\)` in basic mode, `(…)` in `-E` mode; reference with `\1`, `\2`

sed -E 's/(foo)bar/\1baz/' file.txt

Safety habits worth building

1. **Dry-run first** — run without `-i` and eyeball the output before committing to an in-place edit.

2. **Grep before AND after** — confirm the pattern exists before you edit, and confirm it’s gone after:

grep -n "2.1.6" nikto.conf # before

sed -i '' ... nikto.conf

grep -n "2.1.6" nikto.conf # after — should be empty

3. **Back up on anything that matters**: `sed -i.bak ‘…’ file` costs nothing and saves you when a regex is broader than you intended.

4. **Watch for substring collisions** — if one pattern is contained inside another (like `EXECDIR` inside a `DOCDIR` path), order your `-e` replacements from most specific to least specific.

~ik3a

Leave a Reply

Your email address will not be published. Required fields are marked *