Refactoring codebases and batch-editing configuration files in Linux often relies on traditional stream editors like sed or complex find ... -exec perl -pi -e pipelines. While powerful, traditional tools operate “blindly” by default, silently modifying files on disk without offering an interactive visual preview of changes. sad (CLI Search and Displace) is a modern, high-performance batch search-and-replace utility written in Rust. It generates syntax-highlighted unified diffs of prospective substitutions and seamlessly integrates with paging tools like delta before committing changes to disk.
Key Advantages of sad Over Traditional sed
Designed specifically for software engineers and systems administrators, sad bridges the gap between terminal scripting and interactive safety:
- Safe Dry-Run by Default: Executing sad displays prospective modifications as an intuitive coloured diff. It never writes to disk unless explicitly told to do so via the
-c(commit) flag. - Regex Engine: Powered by Rust’s high-speed regular expression engine, supporting PCRE-style patterns, capture groups, and case-insensitive flags.
- Piping Integration: Accepts lists of filenames via standard input (stdin), making it an ideal companion for
fd,rg(ripgrep), andgit status. - Syntax Pager Compatibility: Automatically pairs with modern syntax tools like
deltaordiff-so-fancyfor side-by-side terminal diff visualisation.
Installing sad on Linux
sad is packaged across several distribution repositories and can also be installed using Cargo or pre-compiled binaries:
| Distribution / Platform | Package Manager / Method | Installation Command |
|---|---|---|
| Arch Linux / Manjaro | Pacman (Community) | sudo pacman -S sad |
| Rust / Cargo (Universal) | Cargo Crates.io | cargo install sad |
| Homebrew (Linux / macOS) | Brew | brew install ms-jpq/sad/sad |
| Debian / Ubuntu / RHEL | Pre-compiled GitHub Binary | Manual download → /usr/local/bin |
To install directly from GitHub releases on standard x86_64 Linux systems:
wget https://github.com/ms-jpq/sad/releases/latest/download/x86_64-unknown-linux-musl.zip
unzip x86_64-unknown-linux-musl.zip
sudo mv sad /usr/local/bin/
sudo chmod +x /usr/local/bin/sad
Running Dry-Run Replacements with Unified Diffs
The basic command syntax requires passing files into sad alongside the search pattern and replacement string:
sad [options] <pattern> <replacement> [files...]
For example, to preview replacing an old database host string across all configuration files without modifying them:
sad "db-staging.internal" "db-production.internal" *.conf
sad instantly prints a Git-style unified diff to your terminal screen, showing lines to be removed in red and prospective replacement lines in green.
Pairing sad with fd and ripgrep for Repository-Wide Refactoring
The most powerful workflow pairs sad with fast search utilities to target only files containing the search pattern:
- Find all Python files containing an old function name using
rg(ripgrep):rg -l "calculate_tax_v1" | sad "calculate_tax_v1" "calculate_tax_v2" - Review the printed diff output across every file to verify that method calls, parameters, and comments match your refactoring intentions.
- Once satisfied, append the
-c(or--commit) flag to execute the changes directly:rg -l "calculate_tax_v1" | sad -c "calculate_tax_v1" "calculate_tax_v2"
Useful Options and Regular Expression Grouping
sad supports regular expression capture groups, allowing dynamic pattern transformations:
| Flag / Pattern | Operation | Example Usage |
|---|---|---|
-c, --commit |
Commits modifications to disk directly. | sad -c "foo" "bar" file.txt |
-k, --exact |
Treats pattern as a literal substring rather than a regular expression. | sad -k "http://" "https://" config.json |
$1, $2 (Capture Groups) |
Re-inserts matched regex capture parentheticals into replacement string. | sad 'PORT=(\d+)' 'SERVER_PORT=$1' .env |
-u, --unified |
Specifies number of context lines to display around changes. | sad -u 5 "pattern" "replace" file.txt |