Sed Tester
Write a sed script, paste your text, and watch every address, substitution and hold-space command run on this device.
The output appears here once a script and some input are set.
Patterns are translated POSIX BRE/ERE run on your browser's JavaScript engine — where the two disagree, a note says so on the run itself.
Recipe presets
| What it does | Script | Load |
|---|---|---|
| Reverse the line order (tac) | -n 1!G;h;$p | |
| Double-space the text | G | |
| Number every line | = | |
| Join line pairs | N;s/\n/ | / | |
| Print only lines 2–3 | -n 2,3p | |
| Delete matching lines | /beta/d | |
| Print only the last line | -n $p |
The supported subset
Everything this tool executes, in one table. Anything outside it is refused by name — never silently emulated.
s | s/re/replacement/flags — substitute. Flags: g every match, p print on success, i or I ignore case, or an N-th occurrence number. |
y | y/from/to/ — transliterate each character in from to its partner in to. The lists must be the same length. |
d | d — delete the pattern space and start the next cycle. |
p | p — print the pattern space now. |
P | P — print up to and including the first embedded newline. |
D | D — delete up to the first embedded newline and restart the cycle without reading; with no newline it acts as d. |
q | q — print (unless -n) and quit. Takes at most one address. |
n | n — print (unless -n), then replace the pattern space with the next line; at end of input the run ends. |
N | N — append a newline and the next line to the pattern space; at end of input BSD sed quits without printing. |
= | = — print the current line number on its own line. Takes at most one address. |
h | h — copy the pattern space into the hold space. |
H | H — append a newline and the pattern space to the hold space. |
g | g — replace the pattern space with the hold space. |
G | G — append a newline and the hold space to the pattern space. |
x | x — swap the pattern space and the hold space. |
Refused by name
These forms are refused with a typed message, each traceable to the named manual — emulating them quietly would lie about what runs. -r and s///I work here exactly as they do on BSD; what BSD lacks is refused by name below, never silently emulated.
| Form | Why it refuses | Source |
|---|---|---|
-z | NUL-separated lines are GNU-only; this host's sed rejects -z as an illegal option. | GNU sed manual §2.2 '-z'; BSD sed(1): illegal option |
-s | -s treats each input file separately — GNU-only, and there is one input pane here. | GNU sed manual §2.2 '-s' |
--follow-symlinks | --follow-symlinks changes in-place editing over symlinks — GNU-only, and there are no files here. | GNU sed manual §2.2 |
\U \L \E | \U, \L and \E case conversion is GNU-only — BSD sed prints the letter literally instead of converting. | GNU sed manual §3.5 'The s Command'; BSD prints a literal U (golden gnu-upcase-mangled) |
M | The M multiline flag is GNU-only; BSD sed refuses it as a bad flag. | GNU sed manual §3.5 s-command flags; BSD sed(1): bad flag |
\+ \? \| | \+ \? \| are GNU BRE extensions — BSD treats them as literal characters. Use -E, where + ? | are operators. | GNU sed manual §5.6 'GNU regexp extensions'; POSIX.1-2017 XBD §9.3 has no BRE +/?/| |
a i c | a, i and c insert whole lines of text — real sed, but outside this tool's v1 subset. | POSIX.1-2017 sed 'Editing Commands' (text insertion is outside the v1 subset) |
b t : | b, t and : build loops — real sed, but outside this tool's v1 subset. | POSIX.1-2017 sed 'Editing Commands' (branching is outside the v1 subset — FLAG-G507-2) |
w r W R | w, r, W and R read or write files — there are no files on this page. | POSIX.1-2017 sed w/r; GNU sed manual W/R — there are no files on this page |
F | F prints the current input file name — GNU-only, and there are no files here. | GNU sed manual §3.7 'F' |
e | e executes a shell command — GNU-only, and nothing on this page executes anything. | GNU sed manual §3.7 'e' (command execution never happens here) |
l | l prints a visually unambiguous form — outside this tool's v1 subset. | POSIX.1-2017 sed 'l'; GNU adds a width argument |
{ } | { } group commands under one address — real sed, but outside this tool's v1 subset. | POSIX.1-2017 sed grouped commands (outside the v1 subset) |
[=a=] [.a.] | [=a=] and [.a.] are locale collating expressions — spell the characters out instead. | POSIX.1-2017 XBD §9.3.5 equivalence/collating classes |
\w \s \b | \w, \s and \b are GNU regex extensions (and \d is PCRE, not sed at all) — use POSIX classes such as [[:alnum:]_], [[:space:]] and [[:digit:]]. | GNU sed manual §5.6; POSIX classes [[:alnum:]]/[[:space:]] are the portable spelling |
0,/re/ first~step addr,+N | 0,/re/, first~step and addr,+N are GNU address forms — use line numbers, $, or /regex/ ranges. | GNU sed manual §4.1 'Addresses overview' |
#n | #n as the first script line suppresses default output in POSIX sed — use the -n toggle here instead. | POSIX.1-2017 sed: '#n' as the first line suppresses default output — use the -n toggle instead |
/re/I | /re/I address flags are outside this tool's address subset — use an s command with the I flag. | GNU sed manual §4.1; outside the v1 address subset |
\1 in -E patterns | \1 in an -E pattern is undefined in POSIX and silently never matches on BSD — switch off -E and use \(…\) groups. | POSIX.1-2017 XBD §9.4 (ERE has no backreferences); golden ere-pattern-backref-dead: silently no match on BSD |
Press ? for shortcuts
Do it offline:$ sed 's/old/new/g' input.txt
How to use it
- Write the script in the top-left editor — s/old/new/g to start, or ; and newlines to chain commands such as 2,3p or /error/d.
- Paste the text underneath, or drop a .txt or .log file on the input pane; the file is read by the browser and never sent anywhere.
- Tick -n when only explicit prints should reach the output, and -E when you want ( ) + ? | as operators instead of backslashed BRE forms.
- Switch the right pane to Trace to see each cycle read a line, run every command against it, and print — with the hold space beside it.
- Copy or download the output, hand the whole session over as a state file, or share a link — links carry options only, never your text.
Write a sed script, paste some text, and watch it run one cycle at a time: every address decision, every substitution, and both registers — pattern space and hold space — after each command. Execution stays on this device, in a background worker under a kill timer. The dialect is a pinned subset of BSD sed with POSIX as the floor, and anything outside it is refused by name rather than quietly imitated.
How it works
sed is a stream editor: it never sees the whole document at once. Each cycle it reads one line, strips the trailing newline, and places the line in the pattern space. Every command in the script then runs in order — but only if its address selects the current line. An address can be a line number, $ for the last line, a /regex/, a first,last range, or any of those negated with !. When the script ends, the pattern space is printed with its newline put back — unless -n is set — and the next cycle begins. That auto-print is why p appears to double lines and why -n and p travel together.
The hold space is the second register. It survives across cycles, which is what makes multi-line tricks possible: h and H copy or append the pattern space into it, g and G bring it back, and x swaps the two. The classic reverse-a-file one-liner 1!G;h;$p is nothing but those moves — G glues the accumulated reversal onto every line after the first, h stores the growing result, and $p prints it once at the last line. The trace view exists to make exactly this kind of script legible: it snapshots both registers and everything emitted after every single command.
Regular expressions here are POSIX BRE by default — \( \) groups, \{n,m\} intervals, backreferences \1 through \9 — and ERE with -E, where the brackets drop their backslashes. Patterns are translated and executed by the browser's own JavaScript engine, and where the two regex families genuinely disagree the run says so in a note instead of hiding it. Runs are budgeted: past 200,000 cycles or 2,000,000 command steps the tool refuses with both the budget and the actual count, because a silently truncated answer would look exactly like a correct one.
sed sits in a small family of text tools on this site, and each one keeps its own job: when the work is per-column arithmetic or report shaping rather than per-line editing, hand it to the awk runner; authoring and stress-testing a regular expression on its own is the regex tester's territory; and a one-off rewrite over a pasted body of text with no script syntax at all is what the regex replace workbench is for. This page is where a stream of lines meets a sed script, one cycle at a time.
Examples
alpha one
beta two
gamma three
delta four
one-alpha
two-beta
three-gamma
four-delta
An ERE substitution with two capture groups swaps the words on every line. \1 and \2 read the groups back, and the same script runs unchanged as sed -E on macOS — this exact command is one of the checked-in goldens executed against /usr/bin/sed.
first line
second line
third line
fourth line
second line
third line
The address range 2,3 selects lines two through three and p prints them. Without -n each selected line would appear twice — once from p and once from the end-of-cycle auto-print — which is the single most common surprise in real sed use.
deploy started
cache warmed
ready to serve
ready to serve
cache warmed
deploy started
The reversal classic. On every line but the first, G appends the hold space; h then stores the grown pattern space back; at the last line, $p prints the whole reversed document. Step through it in the Trace view — the hold space column shows the document growing upside down one cycle at a time.
yyy
-y-y-y-
The zero-width edge case: x* matches the empty string at every position, so a global replace inserts a dash before each character and one more at the end — four matches in a three-character line, byte-identical to what BSD sed prints.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A missing final newline survives the round trip
BSD sed still processes a final line that has no trailing newline, and it does not invent one on output: s/o/0/ over the two unterminated lines one, two ends its output mid-line, byte-for-byte. This tool reproduces that, and a note tells you when a run changed the termination of your text.
N at end of input throws the pattern space away here
Run N over a three-line file and BSD sed prints the first joined pair, then quits on the dangling third line without printing it — the golden pack pins that. GNU sed prints the leftover instead (its manual says most seds do not). The same applies to $: it counts input lines, so after N consumes the last line, $ addresses the joined pair.
BRE and ERE disagree about + ? | and one thing JavaScript adds
In the default BRE flavor, + ? | and bare parentheses are literal characters — a+b matches the three characters a+b — and groups are spelled \(…\). With -E they become operators. One honest JavaScript difference rides on top: given a|ab, POSIX takes the longest branch, this page's engine takes the first that matches, and a note on the run says so whenever a pattern carries alternation.
The empty pattern // reuses the last regex that ran
/b/s//X/gp substitutes X for b: the empty s pattern inherits the address regex that just matched. That is real POSIX behaviour, handy for not repeating yourself — and if no regex has run yet, the tool refuses instead of guessing, exactly as sed itself errors on a first empty pattern.
Windows line endings are data, not terminators
sed splits on newline alone, so CRLF text leaves a carriage return at the end of every line. It is invisible, it makes b$ fail to match b, and it is the commonest cause of a substitution that fails only on that one pasted file. Strip the returns first — y or an explicit substitution both do it — or anchor before the character.
Two BSD refusals worth knowing before you script on a Mac
s/a/X/2g is an error on BSD — more than one number or 'g' in substitute flags — where GNU means it as from the second match on; this page refuses it the same way. And in the terminal, sed -i needs an explicit extension on BSD: the bare form sed -i 's/old/new/g' file.txt consumes the script as the backup extension and then fails with invalid command code f because the filename gets parsed as the script. Write sed -i '' 's/old/new/g' file.txt.
Common errors
Line 1, column 8: an occurrence number and g cannot combine on BSD sed — pick the N-th match or every match- GNU sed reads 2g as from the second match onward; BSD refuses the combination outright, and so does this page, because the two dialects would silently give different answers. Use an occurrence number alone, or g alone.
Line 1, column 1: v is not a sed command this tool knows — the supported set is s y d p P D q n N = h H g G x- Usually a quoting slip: a stray character ended up where a command belongs, or a command from another tool's syntax leaked in. The supported subset is printed in full on this page, and everything else refuses with its name.
Line 1, column 5: \U case conversion is GNU-only — BSD sed prints a literal U instead of converting- Case conversion in the replacement is a GNU extension. On a Mac the same script does not error — it quietly writes a literal U into your text, which is worse. A y/// transliteration covers the alphabetic cases portably.
Line 1, column 1: \2 is not defined in the pattern — it opens 1 group- A backreference can only point at a group the pattern actually opens before it. Count the \( pairs — nested groups number by their opening parenthesis, left to right.
Input is larger than the 1 MB limit for this tool — this input is 3.0 MB. For bigger files use the CLI: sed 's/old/new/g' input.txt- A refusal, not a trim: a partial pass would report an answer for text never read. The command line handles any size — and the s/// you already wrote here pastes straight into it.
Stopped after 10 s — this script and input exceeded the time budget on this device.- Runs execute in a background worker under a kill timer: when the timer trips, the worker is destroyed and a fresh one takes the next run, and the page itself stays responsive. Narrow the addresses, or trim the input, and run again.
FAQ
Why does every line print twice?
The end of each cycle auto-prints the pattern space, so an explicit p prints selected lines a second time. Tick -n to suppress the auto-print — the pairing of -n with p, or with the p flag on s///, is the idiomatic way to print only what you chose.
Which sed dialect is this?
A pinned subset of BSD sed — the one macOS ships — with POSIX as the floor: addresses with ranges and negation, s/// with g, p, i/I and an occurrence number, y///, d p q n N P D =, and the hold-space commands h H g G x. Every documented behaviour was executed against /usr/bin/sed and checked in as a golden; GNU differences are cited to the GNU manual, and GNU-only forms refuse by name.
Why does a pattern that works elsewhere match nothing here?
Most pattern playgrounds speak a PCRE-flavoured dialect. POSIX sed has no \d, no lookarounds, and in BRE mode + ? | are literal characters. This page refuses the non-sed escapes by name and points at the POSIX class — [[:digit:]] for \d — instead of letting a pattern silently match nothing.
What is the hold space actually for?
It is the only memory that survives from one line to the next, so it carries anything multi-line: reversing a document, remembering the previous line, or accumulating a block until a delimiter arrives. h, H, g, G and x are the complete instruction set, and the trace shows the register after every one.
Can I edit a file in place here?
No — there are no files on this page, only the text you paste or drop, and nothing is written back anywhere. In a terminal, remember that BSD sed requires an extension argument after -i: sed -i '' 's/old/new/g' file.txt, with the empty string quoted.
Does my text leave this device?
No. The script and the input run in this tab, in a background worker, and the page makes no network request to run them. Share links carry the option toggles and the recipe choice only; the sanctioned way to move a whole session is the state file download, which is a local file you control.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the script now, skipping the debounce.
- ⌘/Ctrl + S
- Download the output as .txt (overrides the browser's save dialog).
- ⌘/Ctrl + C
- Copy the output pane while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the output pane even with a selection active.
- t
- Cycle to the next theme.
- ? or ⌘/Ctrl + /
- Open the shortcut help overlay.
- Esc
- Dismiss the topmost overlay.