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