What Is sed?#
sed (stream editor) reads input line by line, applies editing commands, and writes the result to standard output. It never opens a file in an editor — it processes text as a stream, which makes it ideal for scripting, automation, and quick transformations from the command line.
sed 'command' fileBy default, sed prints every line of input (modified or not) to stdout. The original file is unchanged unless you use the -i flag.
Basic Substitution#
The most common use of sed is find-and-replace with the s (substitute) command:
sed 's/old/new/' file.txtThis replaces the first occurrence of old on each line. To replace all occurrences on a line, add the g (global) flag:
sed 's/old/new/g' file.txtFlags for Substitution#
| Flag | Meaning |
|---|---|
g | Replace all occurrences on the line |
i | Case-insensitive match (GNU sed) |
p | Print the modified line (useful with -n) |
w file | Write matched lines to a file |
2 | Replace only the 2nd occurrence |
Examples:
# Case-insensitive replacement
sed 's/error/WARNING/gi' app.log
# Replace only the second occurrence on each line
sed 's/foo/bar/2' data.txt
# Print only lines where a substitution was made
sed -n 's/DEBUG/INFO/p' app.logAlternate Delimiters#
When your pattern contains /, use a different delimiter to avoid escaping:
# These are equivalent:
sed 's/\/usr\/local\/bin/\/opt\/bin/' config.txt
sed 's|/usr/local/bin|/opt/bin|' config.txt
sed 's#/usr/local/bin#/opt/bin#' config.txtAny character can serve as the delimiter. Pick one that doesn’t appear in your pattern.
In-Place Editing with -i#
To modify a file directly instead of printing to stdout:
sed -i 's/old/new/g' config.confCreate a backup before modifying:
sed -i.bak 's/old/new/g' config.confThis saves the original as config.conf.bak and writes changes to config.conf.
-i with no backup is destructive. On macOS (BSD sed), -i requires an argument — use -i '' for no backup or -i .bak for a backup.Addressing: Targeting Specific Lines#
By default, sed commands apply to every line. Addresses let you target specific lines:
Line Numbers#
# Only line 5
sed '5s/foo/bar/' file.txt
# Lines 10 through 20
sed '10,20s/foo/bar/' file.txt
# From line 3 to the end of the file
sed '3,$s/foo/bar/' file.txt
# Only the last line
sed '$s/foo/bar/' file.txtPattern Addresses#
Target lines matching a regular expression:
# Lines containing "error"
sed '/error/s/foo/bar/' log.txt
# Lines starting with a comment
sed '/^#/s/old/new/' config.conf
# Lines between two patterns (inclusive)
sed '/START/,/END/s/foo/bar/' file.txtNegation#
Use ! to invert the address — apply the command to lines that don’t match:
# Replace on all lines EXCEPT those containing "keep"
sed '/keep/!s/old/new/g' file.txt
# Delete all blank lines
sed '/^$/d' file.txt
# Delete all lines that are NOT blank (inverted)
sed '/^$/!d' file.txtDeleting Lines#
The d command removes lines from the output:
# Delete line 3
sed '3d' file.txt
# Delete lines 10 through 20
sed '10,20d' file.txt
# Delete blank lines
sed '/^$/d' file.txt
# Delete lines containing "DEBUG"
sed '/DEBUG/d' app.log
# Delete comment lines and blank lines
sed '/^#/d; /^$/d' config.confInserting and Appending Lines#
Insert Before a Line#
# Insert a line before line 3
sed '3i\This line was inserted' file.txt
# Insert before every line matching a pattern
sed '/\[section\]/i\# Configuration section' config.iniAppend After a Line#
# Append after line 5
sed '5a\This line was appended' file.txt
# Append after lines matching a pattern
sed '/^server {/a\ # Added by automation' nginx.confReplace an Entire Line#
The c command replaces the entire matched line:
# Replace line 3 entirely
sed '3c\This replaces the entire line' file.txt
# Replace lines matching a pattern
sed '/^hostname=/c\hostname=newserver.example.com' config.confPrinting Specific Lines#
Use -n to suppress default output, then p to print only what you want:
# Print only line 5
sed -n '5p' file.txt
# Print lines 10 through 20
sed -n '10,20p' file.txt
# Print lines containing "error"
sed -n '/error/p' log.txt
# Print from a pattern to end of file
sed -n '/START/,$p' file.txtThis makes sed work like a targeted grep with line-range awareness.
Multiple Commands#
Semicolons#
sed 's/foo/bar/g; s/baz/qux/g' file.txtThe -e Flag#
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txtScript Files#
For complex edits, put commands in a file:
# edits.sed
s/foo/bar/g
s/baz/qux/g
/^#/dsed -f edits.sed file.txtRegular Expressions in sed#
sed uses Basic Regular Expressions (BRE) by default. Use -E (or -r on older systems) for Extended Regular Expressions (ERE):
# BRE: escape grouping and quantifiers
sed 's/\(error\|warn\)/ALERT/' log.txt
# ERE: cleaner syntax with -E
sed -E 's/(error|warn)/ALERT/' log.txtCommon Patterns#
# Remove leading whitespace
sed 's/^[[:space:]]*//' file.txt
# Remove trailing whitespace
sed 's/[[:space:]]*$//' file.txt
# Remove both leading and trailing whitespace
sed 's/^[[:space:]]*//; s/[[:space:]]*$//' file.txt
# Remove HTML tags
sed -E 's/<[^>]+>//g' page.html
# Extract text between quotes
sed -E 's/.*"([^"]+)".*/\1/' file.txtCapture Groups and Back-References#
Captured groups are referenced with \1, \2, etc.:
# Swap first and last name
sed -E 's/^([A-Za-z]+) ([A-Za-z]+)/\2 \1/' names.txt
# Add quotes around each word
sed -E 's/([^ ]+)/"\1"/g' words.txt
# Reformat dates from MM/DD/YYYY to YYYY-MM-DD
sed -E 's|([0-9]{2})/([0-9]{2})/([0-9]{4})|\3-\1-\2|g' dates.txtPractical Examples#
Edit Configuration Files#
# Change a port number
sed -i 's/^port=8080/port=9090/' app.conf
# Uncomment a line
sed -i 's/^#ListenAddress/ListenAddress/' /etc/ssh/sshd_config
# Comment out a line
sed -i '/^PermitRootLogin/s/^/#/' /etc/ssh/sshd_configProcess Log Files#
# Remove timestamps from log lines
sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9:]+//' app.log
# Extract only ERROR lines and strip the level prefix
sed -n '/ERROR/s/.*ERROR //p' app.log
# Replace IP addresses with [REDACTED]
sed -E 's/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[REDACTED]/g' access.logBulk File Edits#
# Replace across multiple files
sed -i 's/oldfunction/newfunction/g' src/*.py
# Add a header to every .sh file
sed -i '1i\#!/bin/bash' scripts/*.sh
# Remove Windows carriage returns
sed -i 's/\r$//' script.shWork with Structured Data#
# Extract values from KEY=VALUE files
sed -n 's/^DB_HOST=//p' .env
# Change a specific key's value
sed -i 's/^DB_HOST=.*/DB_HOST=newdb.example.com/' .env
# Add a line after a specific section header
sed -i '/^\[database\]/a\connection_timeout=30' config.iniCombining sed with Other Commands#
# Transform output from another command
ps aux | sed -n '/nginx/p'
# Use in a pipeline to clean data
cat data.csv | sed '1d' | sed 's/,/\t/g' > data.tsv
# Modify command output before saving
kubectl get pods | sed '1d' | sed 's/ */,/g' > pods.csvsed vs. Other Tools#
| Task | Best tool | Why |
|---|---|---|
| Simple find/replace in files | sed | Fast, scriptable, handles in-place edits |
| Pattern matching and printing | grep | Simpler syntax, better for filtering |
| Field-based text processing | awk | Column awareness built in |
| Complex multi-line transforms | awk or a script | sed multi-line support is awkward |
| Interactive find/replace | Your editor | Visual confirmation |
Common Pitfalls#
Forgetting -i modifies the file. Always test without -i first:
# Preview the changes
sed 's/old/new/g' file.txt
# Then apply
sed -i 's/old/new/g' file.txtGreedy matching. .* matches as much as possible:
# This removes everything between the FIRST < and LAST >
echo "<a>text</a>" | sed 's/<.*>//'
# Output: (empty)
# Use negated character class instead
echo "<a>text</a>" | sed 's/<[^>]*>//g'
# Output: textUnescaped special characters. In BRE, these need escaping: (, ), {, }, +, ?, |. In ERE (-E), they don’t.
macOS vs. Linux. BSD sed (macOS) differs from GNU sed (Linux) in:
-irequires an argument on macOS (-i '')- Some flags like
\tfor tab don’t work — use a literal tab or$'\t' -Eworks on both, but-ris GNU-only
Quick Reference#
| Command | What it does |
|---|---|
s/old/new/ | Replace first occurrence |
s/old/new/g | Replace all occurrences |
d | Delete the line |
p | Print the line |
i\text | Insert text before the line |
a\text | Append text after the line |
c\text | Replace the entire line |
q | Quit (stop processing) |
= | Print the line number |
| Address | What it matches |
|---|---|
5 | Line 5 |
5,10 | Lines 5 through 10 |
$ | Last line |
/pattern/ | Lines matching the pattern |
/start/,/end/ | Range between two patterns |
! | Negate (invert the match) |
| Flag | What it does |
|---|---|
-n | Suppress automatic printing |
-i | Edit file in place |
-i.bak | Edit in place, keep backup |
-E | Use extended regular expressions |
-e | Add a command |
-f file | Read commands from a file |


