Introduction
sd (stream editor, but friendlier) is a Rust utility that does what most people actually use sed for: find and replace, possibly with regex, possibly in place. It throws out sed's cryptic single-letter command language and inconsistent BSD vs GNU behavior, leaving a single clean interface.
With over 7,000 GitHub stars, sd is the "just works" replacement for 90% of sed invocations. The other 10% — complex multi-line addressing, d/p/y commands — still need sed or awk, but for the common case, sd is faster and easier to remember.
What sd Does
sd takes two positional arguments: the pattern (regex by default) and the replacement. Flags control in-place editing (-i), literal strings (-s), preview (-p), and file-list mode (-f). Capture groups work with $1 $2 etc. The regex engine is Rust's regex crate (Perl-like, not POSIX), so features like non-greedy quantifiers and lookarounds work as expected.
Architecture Overview
stdin / file
|
[sd (Rust)]
arg 1: PATTERN
arg 2: REPLACEMENT
|
[Regex engine (Rust `regex`)]
Perl-like syntax
named + numbered captures
|
[Substitution]
$1, $2, ${name} for captures
no re-escaping madness
|
stdout / in-place file editSelf-Hosting & Configuration
# Common tasks
# Rename imports across a TS repo (preview first)
sd -p '@oldorg/(\w+)' '@neworg/$1' src/**/*.ts
sd '@oldorg/(\w+)' '@neworg/$1' src/**/*.ts
# Fix trailing whitespace
sd ' +$' '' **/*.md
# Rewrite URLs in docs
sd 'https://old.example.com' 'https://new.example.com' docs/**/*.md
# Literal string (no regex)
sd -s '.foo.' '.bar.' file.txt
# Use with find + xargs for portability
find . -name '*.js' -print0 | xargs -0 sd 'const (' 'let (' Key Features
- Clean syntax — 2 args: pattern and replacement (vs sed's
s/foo/bar/g) - Perl regex — non-greedy, lookahead/lookbehind, named captures
- In-place editing — no
-i.bakdrama, uses atomic rename - Preview mode —
-pshows what would change without writing - Literal mode —
-sfor literal string replace (no regex escaping) - Cross-platform — same behavior on macOS, Linux, Windows (no BSD/GNU split)
- Fast — Rust regex engine, multi-file in parallel
- Unicode aware — UTF-8 by default
Comparison with Similar Tools
| Feature | sd | sed | perl -pi -e | awk | rg --replace |
|---|---|---|---|---|---|
| Learning curve | Very low | High (arcane) | Medium | High | Very low |
| Regex flavor | Rust (Perl-like) | POSIX BRE/ERE | Perl | POSIX ERE | Rust (Perl-like) |
| In-place | Yes (-i) | Yes (-i, tricky flags) | Yes (-i) | Need wrapper | Yes (--replace with rewrite) |
| Cross-platform consistency | Yes | BSD/GNU differ | Yes | Varies | Yes |
| Multi-file parallelism | Yes | Sequential | Sequential | Sequential | Yes |
| Best For | Find/replace | Scripting, everywhere | Advanced text work | Complex transforms | Repo-wide rewrite |
FAQ
Q: When should I still use sed? A: For multi-line addressing, conditional logic, delete/print operations, or strict POSIX scripting. sd focuses on find/replace only.
Q: sd vs ripgrep --replace?
A: rg --replace shows you matches with replacements but doesn't write by default (you pipe to sponge or use rg -r ... --files-with-matches | xargs sed ...). sd writes in-place cleanly. Use rg to preview matches, sd to apply changes.
Q: Does it respect .gitignore?
A: Not natively. Combine with rg --files -l to get the list of files first, then pipe to sd.
Q: Safe to use with large files? A: Yes — it streams input, not loads the whole file. In-place edits use a temp file + atomic rename so crashes don't corrupt your data.
Sources
- GitHub: https://github.com/chmln/sd
- License: MIT