sed
sed (Stream Editor) processes text line by line, applying editing commands like substitution, deletion, and insertion. It is the standard tool for find-and-replace operations on files and streams, used in scripts to modify config files, transform log output, and perform batch text transformations.
Understanding sed
What Is sed in Simple Terms
sed reads input line by line, applies transformation commands, and writes the result. The most common use is substitution: replace this text with that text. Unlike a text editor, sed works non-interactively — perfect for scripted config file modifications.
sed 's/localhost/prod-db.internal/g' config.template > config.prod — replaces every occurrence of localhost with prod-db.internal and saves to a new file. One command, zero manual editing.
+------------------------------------------+| Input stream (file or stdin) |+------------------------------------------+ | line by line | v+------------------------------------------+| sed 's/localhost/10.0.2.100/g' || Pattern space: current line || Apply substitution command || s/old/new/g -- replace all occurrences |+------------------------------------------+ | v+------------------------------------------+| Output stream (modified lines) || localhost -> 10.0.2.100 |+------------------------------------------+Practical Commands
## Basic substitution: s/old/new/sed 's/localhost/10.0.2.100/' config.yaml## Only replaces FIRST occurrence per line ## Global substitution (all occurrences per line)sed 's/localhost/10.0.2.100/g' config.yaml ## Case-insensitive substitutionsed 's/error/ERROR/gI' /var/log/app.log ## In-place edit (modifies the file directly)sed -i 's/debug: true/debug: false/' app.yaml ## In-place with backupsed -i.bak 's/debug: true/debug: false/' app.yaml## Creates app.yaml.bak with original content ## Delete lines matching patternsed '/^#/d' config.yaml ## remove comment linessed '/^$/d' config.yaml ## remove blank linessed '/DEBUG/d' app.log ## remove debug log lines ## Print specific linessed -n '10,20p' /var/log/app.log ## lines 10-20sed -n '/ERROR/p' /var/log/app.log ## only error lines ## Insert line before patternsed '/^\[Service\]/i User=payment-svc' service.unit ## Append line after patternsed '/^\[Service\]/a Restart=on-failure' service.unit ## Multiple expressions with -esed -e 's/localhost/10.0.2.100/g' -e 's/5432/5433/g' config.yaml ## Replace using delimiter other than / (useful when pattern contains /)sed 's|/old/path|/new/path|g' config.yaml ## Production patterns: ## Remove trailing whitespacesed -i 's/[[:space:]]*$//' file.txt ## Extract lines between two patternssed -n '/START/,/END/p' file.txt ## Comment out a line matching patternsed -i '/PasswordAuthentication yes/s/^/#/' /etc/ssh/sshd_configTroubleshooting
| Symptom | Command | What to Check |
|---|---|---|
| Substitution not working | Test without -i first | Preview before in-place edit |
| Special chars not matching | Escape: \. \* \/ |
Regex metacharacters |
| sed -i differs on macOS | Use sed -i '' on macOS |
macOS sed requires explicit backup suffix |
Common MistakeUsing
sed -iwithout testing the expression first. Always runsed 's/old/new/g' file(without -i) to preview the output before modifying the file in place. One wrong regex can corrupt a config file.
TipWhen the pattern contains forward slashes (like file paths), use a different delimiter:
sed 's|/etc/nginx|/etc/nginx-new|g'. sed accepts any character aftersas the delimiter —|,,,@, or#all work.
Frequently Asked Questions
Why do people reach for sed instead of just editing a file directly for scripted changes?
sed processes a stream non-interactively, which means the same substitution can run identically across hundreds of files or as part of an automated pipeline (CI script, config templating, log transformation) with no manual editing step. Its core strength is line-oriented substitution via regex — `sed 's/old/new/g'` — but it also supports deletion, insertion, and multi-line pattern-space operations, all scriptable and reproducible in a way manual editing never is.
What's the classic sed gotcha involving in-place editing across platforms?
GNU sed's `-i` flag takes an optional suffix argument directly (`sed -i.bak 's/x/y/'` or `sed -i ''` with no suffix), but BSD/macOS sed requires the suffix argument even when empty (`sed -i '' 's/x/y/'`) — a script written and tested on Linux frequently breaks silently or errors out on macOS because of this exact syntax difference. Scripts meant to be portable should detect the platform or avoid `-i` in favor of writing to a temp file and moving it.