sed — Stream Editor for Text Transformation
Filter and transform text with sed — substitution, in-place editing, line addressing, deletion and back-references for scripts and pipelines.
sed (stream editor) reads text line by line and applies editing commands as the data flows through – no interactive editor, no temp files. Its bread and butter is search-and-replace with s/pattern/replacement/, but it also deletes, inserts, prints and reorders lines, addressed by number or by regex. You will reach for it whenever you need to patch config files, rewrite URLs, strip whitespace or massage command output in a pipeline. This guide walks from basic substitution through in-place editing, line addressing and back-references to the recipes you actually use.
Basic Substitution
sed 's/<pattern>/<replacement>/' <file> — Replace the first occurrence of pattern on each line.
sed 's/foo/bar/' input.txtsed 's/<pattern>/<replacement>/g' <file> — Replace all occurrences of pattern on each line (global).
sed 's/foo/bar/g' input.txtsed 's/<pattern>/<replacement>/gi' <file> — Replace all occurrences, case-insensitive.
sed 's/error/warning/gi' log.txtsed 's/<pattern>/<replacement>/2' <file> — Replace only the Nth occurrence of pattern on each line.
sed 's/the/THE/2' input.txtsed 's/<pattern>/<replacement>/gp' <file> — Replace globally and print only the changed lines (use with -n).
sed -n 's/error/ERROR/gp' log.txtIn-Place Editing
sed -i 's/<pattern>/<replacement>/g' <file> — Edit the file in-place (modifies the original file directly).
sed -i 's/localhost/production.example.com/g' config.ymlsed -i.bak 's/<pattern>/<replacement>/g' <file> — Edit in-place and create a backup with the given suffix.
sed -i.bak 's/debug=true/debug=false/g' config.inised -i '' 's/<pattern>/<replacement>/g' <file> — Edit in-place without backup (macOS/BSD syntax, empty suffix required).
sed -i '' 's/old/new/g' config.ymlsed -i 's/<pattern>/<replacement>/g' <file1> <file2> — Edit multiple files in-place with the same substitution.
sed -i 's/v1.0/v2.0/g' README.md CHANGELOG.mdDelimiters & Special Characters
sed 's|<pattern>|<replacement>|g' <file> — Use | as delimiter instead of /. Useful when patterns contain slashes.
sed 's|/usr/local|/opt|g' paths.confsed 's#<pattern>#<replacement>#g' <file> — Use # as delimiter. Any character can serve as delimiter.
sed 's#http://#https://#g' urls.txtsed 's/[[:space:]]*$//' <file> — Remove trailing whitespace from each line.
sed 's/[[:space:]]*$//' source.pysed 's/^[[:space:]]*//' <file> — Remove leading whitespace from each line.
sed 's/^[[:space:]]*//' messy.txtsed 's/&/\&/g; s/</\</g; s/>/\>/g' <file> — Escape HTML special characters.
sed 's/&/\&/g; s/</\</g; s/>/\>/g' input.htmlAddress Selection (Line Targeting)
sed '<n>s/<pattern>/<replacement>/' <file> — Substitute only on a specific line number.
sed '3s/old/new/' config.txtsed '<n>,<m>s/<pattern>/<replacement>/g' <file> — Substitute on a range of lines (from line n to line m).
sed '10,20s/foo/bar/g' data.txtsed '$s/<pattern>/<replacement>/' <file> — Substitute only on the last line. $ addresses the last line.
sed '$s/$/;/' data.csvsed '/<regex>/s/<pattern>/<replacement>/g' <file> — Substitute only on lines matching a regex pattern.
sed '/^#/s/TODO/DONE/g' script.shsed '/<start>/,/<end>/s/<pattern>/<replacement>/g' <file> — Substitute within a range defined by two regex patterns.
sed '/<body>/,/<\/body>/s/class="old"/class="new"/g' page.htmlsed '1,/<pattern>/s/<old>/<new>/g' <file> — Substitute from the first line until a pattern is matched.
sed '1,/---/s/draft/published/g' post.mdsed '0~2s/<pattern>/<replacement>/g' <file> — Substitute on every 2nd line (GNU sed step address: start~step).
sed '0~2s/^/>> /' data.txtDeleting Lines
sed '<n>d' <file> — Delete a specific line by number.
sed '5d' data.txtsed '<n>,<m>d' <file> — Delete a range of lines.
sed '3,7d' data.txtsed '$d' <file> — Delete the last line of the file.
sed '$d' data.txtsed '/<pattern>/d' <file> — Delete all lines matching a pattern.
sed '/^#/d' config.inised '/^$/d' <file> — Delete all empty lines.
sed '/^$/d' messy.txtsed '/^[[:space:]]*$/d' <file> — Delete all blank lines (empty or whitespace-only).
sed '/^[[:space:]]*$/d' messy.txtsed '/<start>/,/<end>/d' <file> — Delete all lines between two patterns (inclusive).
sed '/BEGIN_GENERATED/,/END_GENERATED/d' output.txtsed '/<pattern>/!d' <file> — Delete all lines NOT matching a pattern (inverse, like grep).
sed '/ERROR/!d' log.txtInserting & Appending
sed '<n>i\<text>' <file> — Insert text before a specific line.
sed '1i\# Configuration File' config.inised '<n>a\<text>' <file> — Append text after a specific line.
sed '5a\# New section starts here' config.inised '/<pattern>/i\<text>' <file> — Insert text before lines matching a pattern.
sed '/\[database\]/i\# Database settings' config.inised '/<pattern>/a\<text>' <file> — Append text after lines matching a pattern.
sed '/^server {/a\ listen 443 ssl;' nginx.confsed '<n>c\<text>' <file> — Replace (change) an entire line with new text.
sed '3c\new_value = true' config.inised '/<pattern>/c\<text>' <file> — Replace entire lines matching a pattern with new text.
sed '/^debug=/c\debug=false' config.iniBack-References & Groups
sed 's/\(<pattern>\)/\1<suffix>/g' <file> — Capture a group with ( ) and reference it with \1 in the replacement.
sed 's/\(version\)=.*/\1=2.0/' config.inised -E 's/(<pattern>)/\1<suffix>/g' <file> — Extended regex mode. Use ( ) for groups instead of ( ).
sed -E 's/(version)=.*/\1=2.0/' config.inised -E 's/(<p1>)(<p2>)/\2\1/g' <file> — Swap two captured groups using back-references.
sed -E 's/([a-z]+), ([a-z]+)/\2 \1/g' names.txtsed 's/.*/(&)/' <file> — The & in replacement refers to the entire matched text.
sed 's/.*/(&)/' list.txtsed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/g' <file> — Reformat dates from YYYY-MM-DD to DD.MM.YYYY using three groups.
sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/g' dates.txtPrinting & Output Control
sed -n '<n>p' <file> — Print only a specific line. -n suppresses default output.
sed -n '10p' data.txtsed -n '<n>,<m>p' <file> — Print a range of lines.
sed -n '5,15p' data.txtsed -n '/<pattern>/p' <file> — Print only lines matching a pattern (like grep).
sed -n '/ERROR/p' log.txtsed -n '/<start>/,/<end>/p' <file> — Print lines between two patterns (inclusive).
sed -n '/BEGIN/,/END/p' config.txtsed -n '$=' <file> — Print the total number of lines in the file (like wc -l).
sed -n '$=' data.txtsed '/<pattern>/q' <file> — Quit after printing the first line matching a pattern.
sed '/^END$/q' stream.txtMultiple Commands
sed -e 's/<p1>/<r1>/g' -e 's/<p2>/<r2>/g' <file> — Apply multiple substitution commands with -e flags.
sed -e 's/foo/bar/g' -e 's/baz/qux/g' input.txtsed 's/<p1>/<r1>/g; s/<p2>/<r2>/g' <file> — Chain multiple commands with semicolons.
sed 's/http/https/g; s/www\.//g' urls.txtsed -f <script_file> <file> — Read sed commands from a script file (one command per line).
sed -f transforms.sed input.txtsed '{ s/<p1>/<r1>/g; s/<p2>/<r2>/g; }' <file> — Group multiple commands with curly braces.
sed '/^title/{ s/old/new/g; s/draft/final/g; }' document.mdTransliteration
sed 'y/<source_chars>/<dest_chars>/' <file> — Transliterate characters (like tr). Maps each character one-to-one.
sed 'y/abc/ABC/' input.txtsed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' <file> — Convert all uppercase letters to lowercase.
sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' input.txtCommon Recipes
sed -E 's/^[[:space:]]+|[[:space:]]+$//g' <file> — Trim leading and trailing whitespace from each line.
sed -E 's/^[[:space:]]+|[[:space:]]+$//g' messy.txtsed '/^$/N;/^\n$/d' <file> — Squeeze multiple consecutive blank lines into one.
sed '/^$/N;/^\n$/d' messy.txtsed 's/^/ /' <file> — Indent every line by 4 spaces.
sed 's/^/ /' code.pysed '=' <file> | sed 'N;s/\n/\t/' — Add line numbers followed by a tab to each line.
sed '=' script.sh | sed 'N;s/\n/\t/'sed -E 's/([^ ]+)/"\1"/g' <file> — Wrap each word in double quotes.
sed -E 's/([^ ]+)/"\1"/g' words.txtsed -E 's/,.*//' <file> — Extract the first field from a CSV (everything before the first comma).
sed -E 's/,.*//' data.csvsed -e :a -e '/\\$/N; s/\\\n//; ta' <file> — Join lines ending with a backslash (line continuation).
sed -e :a -e '/\\$/N; s/\\\n//; ta' MakefilePipelines
<command> | sed 's/<pattern>/<replacement>/g' — Use sed as a filter in a pipeline to transform output.
cat /etc/passwd | sed 's/:.*//'<command> | sed -n '/<pattern>/p' — Filter output to show only matching lines.
env | sed -n '/^PATH/p'<command> | sed '1d' — Remove the first line (header) from command output.
docker ps | sed '1d'<command> | sed 's/\x1b\[[0-9;]*m//g' — Strip ANSI color codes from command output.
ls --color=always | sed 's/\x1b\[[0-9;]*m//g' Conclusion
sed turns repetitive text edits into one-liners you can drop into scripts and pipelines. For everyday work, s///g, line deletion with d and selective printing with -n …p cover most cases. The one flag to treat with respect is -i: it overwrites the original file with no undo, so get into the habit of writing -i.bak to keep a backup – or run the command without -i first and eyeball the output. Be aware of GNU/BSD differences: GNU sed takes -i with no argument, whereas BSD/macOS sed requires sed -i ''; step addresses like 0~2 and \x1b escapes are GNU extensions too.
Further Reading
- GNU sed manual – complete reference with all commands and addressing modes
- grymoire sed tutorial – classic, example-driven introduction to sed