Memory-safe, 100% drop-in replacement for GNU ed 1.22.2 written in Rust.
- ✅ 100% GNU ed 1.22.2 compatible - Verified with 119 differential tests
- ✅ Memory safe - No buffer overflows, use-after-free, or undefined behavior
- ✅ Zero unsafe code - All core functionality in safe Rust
- ✅ Drop-in replacement - Identical command-line interface and behavior
- ✅ Containerized testing - Both implementations tested in identical environments
# Linux (native)
cargo build --release
# Linux (static musl binary)
cargo build --release --target x86_64-unknown-linux-musl
# macOS
cargo build --releaseThe binary will be at target/release/rust-ed
# Install to ~/.cargo/bin/rust-ed
cargo install --path .
# Add to PATH or create symlink
sudo ln -sf ~/.cargo/bin/rust-ed /usr/local/bin/edLinux:
# Build static binary for maximum portability
cargo build --release --target x86_64-unknown-linux-musl
# Install to /usr/local/bin (preferred for user-managed binaries)
sudo cp target/x86_64-unknown-linux-musl/release/rust-ed /usr/local/bin/ed
# Or replace system ed (backup first!)
sudo mv /usr/bin/ed /usr/bin/ed.gnu.backup
sudo cp target/x86_64-unknown-linux-musl/release/rust-ed /usr/bin/edmacOS:
# Build native macOS binary
cargo build --release
# Install to /usr/local/bin
sudo cp target/release/rust-ed /usr/local/bin/ed
# Note: macOS ships with BSD ed, not GNU ed
# rust-ed provides GNU ed 1.22.2 behavior on macOSHomebrew (Future):
# When published to Homebrew
brew install rust-ed
brew link rust-ed# Install directly from crates.io
cargo install rust-ed
# Binary will be at ~/.cargo/bin/rust-ed
# Then symlink or copy to desired locationInstall rust-ed on your system:
# Builds and installs rust-ed, automatically backs up GNU ed
just install-rust-ed
# This will:
# - Build the static musl binary
# - Backup /usr/bin/ed to /usr/bin/ed.gnu
# - Install rust-ed as /usr/bin/edRestore GNU ed:
# Restores GNU ed from backup
just install-gnu-ed
# This will:
# - Remove rust-ed from /usr/bin/ed
# - Restore /usr/bin/ed.gnu to /usr/bin/edCheck which ed is installed:
# Shows which ed version is currently active
just which-ed
# Output shows:
# - Whether it's a symlink or regular file
# - Location and backup status
# - Version information
# - File type details# Test the installation
echo "Hello, ed!" | ed
# Check version (shows compatibility with GNU ed 1.22.2)
ed --version
# Run simple editing test
echo -e "a\ntest line\n.\nw /tmp/test.txt\nq" | ed
cat /tmp/test.txt # Should show "test line"During development and testing, you can easily swap between rust-ed and GNU ed:
# Install rust-ed for testing
just install-rust-ed
# Test your workflows with rust-ed
# ... run your scripts, tests, etc ...
# Switch back to GNU ed
just install-gnu-ed
# Compare behavior
# ... verify differences ...
# Check which one is active
just which-edThis is particularly useful for:
- Differential testing - Compare behavior side-by-side
- Regression testing - Ensure rust-ed matches GNU ed exactly
- Production validation - Test real-world scripts with both implementations
- GNU ed present: Most distributions include GNU ed in base system
- Replacement strategy: rust-ed is a drop-in replacement
- Static builds: Use musl target for maximum portability across distros
- BSD ed by default: macOS ships with BSD ed (different from GNU ed)
- No GNU ed: GNU ed is not included in macOS by default
- rust-ed provides: Full GNU ed 1.22.2 behavior on macOS
- Testing: Install rust-ed to get GNU ed compatibility on Mac
- Homebrew alternative:
brew install edinstalls GNU ed (if you want C version)
- No built-in ed: iOS does not ship with any ed implementation
- Not applicable: iOS apps run in sandboxes, command-line tools not accessible
- Jailbreak only: Would require jailbroken device to use command-line ed
rust-ed is a drop-in replacement for GNU ed:
rust-ed [file]
rust-ed -p '*' myfile.txt # Prompt mode
rust-ed -s script.ed input.txt # Script modeAll GNU ed commands and flags are supported.
rust-ed uses containerized differential testing to verify 100% compatibility with GNU ed 1.22.2. Both implementations run in identical Docker containers - the only difference is the binary (C vs Rust).
Run all tests (119 tests):
just test-drop-in-automatedTest specific commands:
just test-delete # Test delete command (d)
just test-substitute # Test substitute command (s)
just test-write # Test write command (w, W)See justfile for all available test commands.
- Docker (for building test containers)
- Rust 1.70+ with Cargo
- Just (command runner) -
cargo install just
# Build GNU ed reference container
docker build -f docker/Dockerfile.gnu-ed -t gnu-ed:latest .
# Build rust-ed container
docker build -f docker/Dockerfile.rust-ed -t rust-ed:latest .The GNU ed container builds from the included source tarball (gnu-ed-source/ed-1.22.2.tar) ensuring reproducible test results.
rust-ed mirrors GNU ed's architecture while leveraging Rust's safety features:
- buffer.rs - Line buffer management with bounds checking
- main_loop.rs - Command execution loop
- io.rs - Safe file operations
- regex.rs - Pattern matching with
regexcrate - global.rs - Global command implementation
- error.rs - GNU ed compatible error handling
- signal.rs - POSIX signal handling
- 119 automated tests covering all 32 GNU ed commands
- 100% command coverage - Every GNU ed command tested
- Symmetric containerized testing - Both binaries in identical environments
- Byte-for-byte output verification - Exit codes, stdout, stderr, and file state
tests/
├── differential_containerized.rs # Main test runner
└── common/suites/ # Test definitions (27 files)
├── cmd_append.rs # 'a' command tests
├── cmd_delete.rs # 'd' command tests
├── cmd_substitute.rs # 's' command tests
└── ... # One file per command
See tests/README.md for detailed testing documentation.
rust-ed is licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
The gnu-ed-source/ directory contains an unmodified upstream GNU ed 1.22.2
tarball, used solely to build the reference container for differential
testing. It is distributed under the GNU General Public License v3.0 and is
not part of the rust-ed implementation.
Contributions are welcome! Please ensure:
- All tests pass:
just test-drop-in-automated - Code follows rustfmt:
cargo fmt - No clippy warnings:
cargo clippy - Behavior matches GNU ed 1.22.2 exactly
- GNU ed 1.22.2: https://www.gnu.org/software/ed/
- GNU ed Manual: https://www.gnu.org/software/ed/manual/ed_manual.html
- Target version info:
gnu-ed-source/VERSION.txt
rust-ed is feature-complete and achieves 100% compatibility with GNU ed 1.22.2:
- ✅ All 32 commands implemented
- ✅ All address modes supported
- ✅ All command flags implemented
- ✅ Signal handling matches GNU ed
- ✅ Error handling matches GNU ed
- ✅ Exit codes match exactly
The project is ready for production use as a drop-in replacement for GNU ed.