Replace Text
The substitute command is most of what sed gets used for. replaces the first occurrence on each line; makes it every occurrence.
| Command | What it does |
|---|---|
| Replace the first match on each line | |
| Replace every match ( = global) | |
| Replace only the 2nd match on each line | |
| Case-insensitive match (GNU sed; BSD lacks ) | |
| Any delimiter works; use or when the text has slashes | |
| is the whole match: error becomes [error] | |
| Substitute only on lines matching a pattern | |
| Substitute only on line 3 | |
| Strip trailing whitespace | |
| Works on piped input too (GNU sed prints as newline) |
Edit Files In Place
Without , sed prints the result and leaves the file alone. That is the safe way to test an expression first.
is the one flag that is not portable, and it is the single most common reason a sed command fails. GNU sed on Linux takes . BSD sed on macOS reads that as a backup filename extension and stops with or ; it needs an empty argument, . Only runs unchanged on both.
| Command | What it does |
|---|---|
| Dry run: prints the result, file untouched | |
| Edit the file in place (GNU sed / Linux only) | |
| The same edit on macOS (BSD sed) | |
| In place, keeping the original as file.bak (works everywhere) | |
| The portable long way, no at all |
sed on macOS
macOS ships BSD sed, and the biggest difference is : BSD requires a backup extension argument, GNU does not. on a Mac fails with "invalid command code" or "undefined label" because gets read as the backup extension.
| Command | What it does |
|---|---|
| In-place edit on macOS (empty string = no backup) | |
| Portable form: same command on macOS and Linux | |
| Portable, without keeping the backup | |
| Installs GNU sed as , which takes Linux syntax |
Other BSD gaps to know: no case-insensitive flag, and / insert text needs a real newline after the backslash. for extended regex works on both.
Multiple Files
sed takes as many files as you give it, but rewrites every one of them. Run the command without on a single file first.
| Command | What it does |
|---|---|
| Edit every .conf in the directory | |
| Edit every matching file in a tree (see the grep cheat sheet) | |
| Same, safe with spaces in filenames | |
| The find equivalent | |
| The macOS spelling of that command | |
| Read many files without changing any of them | |
| With , is each file's last line, not the last file's |
Recursion is the caller's job: sed itself has no recursive flag ( means extended regex). Filtering with first also keeps the mtime of files that did not match.
Delete Lines
| Command | What it does |
|---|---|
| Delete lines matching a pattern | |
| Delete empty lines | |
| Delete comments and empty lines | |
| Delete the first line (drop a header) | |
| Delete the last line | |
| Delete lines 2 through 5 | |
| Delete from line 10 to the end | |
| Delete from one pattern to another, inclusive | |
| Delete everything except matching lines (same as ) |
Print Lines (-n and p)
turns off the default print-every-line behaviour, so prints only what you select.
| Command | What it does |
|---|---|
| Print line 5 only | |
| Print lines 2 through 4 | |
| Print the last line | |
| Print matching lines (grep in sed clothing) | |
| Print from one pattern to another | |
| Print the first 10 lines, then quit (fast on huge files) | |
| Every 3rd line starting at 1 (GNU only) | |
| Print only the rewritten lines: extract a value | |
| Write matching lines to another file () | |
| Print the line numbers of matches, not the lines |
Insert and Append
inserts before a line, appends after it, replaces it entirely.
| Command | What it does |
|---|---|
| Insert a line at the top (GNU syntax) | |
| Append a line at the end | |
| Add a line after each match | |
| Add a line before each match | |
| Replace the whole matching line | |
| Append after a specific line number |
BSD/macOS sed wants a backslash and a literal newline after , , and ; the one-line GNU forms above fail there. Use , or:
sed -i '' '1i\
header line
' fileRegex and Capture Groups
sed's default dialect is basic regex (BRE): groups and / need backslashes. switches to extended regex and works on both GNU and BSD sed ( is the older GNU spelling).
| Command | What it does |
|---|---|
| BRE capture groups: "Doe, Jane" becomes "Jane Doe" | |
| Same with -E: no backslashes on the parens | |
| (one or more) needs -E | |
| (optional) needs -E | |
| Alternation needs -E | |
| The BRE spelling of | |
| First field of a colon-separated file | |
| Collapse runs of whitespace |
sed has no or in any dialect: use and . is greedy and there are no lazy quantifiers, so match "up to the next X" with .
Multiple Commands
| Command | What it does |
|---|---|
| Run several expressions in order | |
| Same, separated by semicolons | |
| Group commands to run on matching lines ( steps to the next line) | |
| Read commands from a script file, one per line | |
| Join lines in pairs: pulls in the next line, then replace the newline |
sed works line by line, so a plain never matches. The classic join-all-lines one-liner pulls the file into the buffer first (GNU sed):
sed ':a;N;$!ba;s/\n/ /g' fileFor simple newline jobs, or is easier to read.
Variables and Special Characters
| Command | What it does |
|---|---|
| Double quotes let the shell expand | |
| Another delimiter when the variable holds slashes | |
| Command substitution works too | |
| A literal in the replacement must be escaped | |
| A literal backslash is (doubled again by shell quoting) | |
| To match a literal , escape it in the pattern | |
| Escape to match them literally | |
| Remove every double quote from the text | |
| Remove every single quote (swap the outer quotes round) | |
| A literal inside a single-quoted expression: close, escape, reopen |
Options
The shape is . Everything else is a command letter inside the script.
| Option | What it does |
|---|---|
| Suppress the automatic print, so only outputs | |
| Add an expression; repeat it for several | |
| Read the commands from a file | |
| Edit in place (GNU); on macOS it must be | |
| Edit in place and keep a backup, the portable spelling | |
| Extended regex: , , and need no backslash | |
| GNU-only spelling of ; prefer | |
| Treat each input file separately, so is its own last line | |
| Split input on NUL, for pairing with (GNU) | |
| Show how GNU sed parses and runs the script | |
| Tells you whether you have GNU sed or BSD sed |
Command Letters
| Letter | What it does |
|---|---|
| Substitute, the command nearly every script uses | |
| Transliterate character by character, like | |
| Delete the line | |
| Print the line, normally with | |
| Append a line after this one | |
| Insert a line before this one | |
| Replace the whole line | |
| Quit without reading the rest of the input | |
| Print the line number | |
| Write the line to a file | |
| Read a file in after the line | |
| Print the current line and load the next | |
| Add the next line to the buffer, keeping both | |
| Copy, append and swap with the hold space | |
| Branch and loop, what is built from | |
| Show invisible characters, with marking the line end |
is the quickest way to see a stray carriage return or a tab that a pattern keeps missing.
sed on Windows
Windows has no built-in sed. Git Bash and WSL both ship GNU sed, so Linux syntax works as written; means the shell is cmd or PowerShell rather than one of those.
| Command | What it does |
|---|---|
| Works unchanged in Git Bash and WSL (GNU sed) | |
| Call Linux sed from PowerShell or cmd | |
| The PowerShell equivalent, no sed needed | |
| Strip the carriage returns a Windows editor leaves behind | |
| Fixes on a script edited in Windows |
Carriage returns are the usual reason a pattern anchored with matches nothing on a file that came from Windows.
Gotchas
- needs on macOS and plain on Linux. is the only spelling that works on both unchanged. and on a Mac are almost always this.
- is BSD sed refusing the one-line GNU , and forms. Add the backslash and a real newline, or use .
- usually means the delimiter also appears inside your pattern or replacement, or the expression reached sed unquoted.
- No , no , no lazy in sed regex, in any version. Use , , and .
- An unescaped in the replacement inserts the whole match. This bites when the replacement is a shell variable containing .
- Prefer over for extended regex: GNU sed takes both, BSD sed only .
- Single-quote sed expressions unless you need a variable expanded. Inside double quotes the shell eats backslashes and before sed sees them.
- grep answers "which lines", sed rewrites them, awk works per column. See the grep cheat sheet and awk cheat sheet.