When to use what#

Need

Use

Interactive shell / scripts

rtrash CLI (or multi-call trash-put etc.)

Safer than permanent delete in Python

rtrash.unlink(path) (after importing rtrash)

Drop-in mental model for rm

rtrash -rf path or symlink rm → put

Permanent purge of trash entries

rtrash empty / rtrash rm PATTERN

Windows system Recycle Bin

` rtrash put/list/restore/empty` (from source; not FreeDesktop layout)

macOS Finder Trash

Not supported — experimental FreeDesktop home trash only

Safety model and FreeDesktop layout: architecture.org. Measured comparison to Python trash-cli: benchmarks.org. Python API detail: bindings.org.

Install#

Published on crates.io and PyPI.

CLI (Rust)#

cargo install rtrash          # from crates.io (needs Rust toolchain)
# or prebuilt musl on x86_64 / aarch64 Linux:
cargo binstall rtrash
rtrash setup

rtrash setup installs multi-call links, bash/zsh/fish completions, and the man page under ~/.local from assets embedded in the binary (no source checkout). Flags: --dry-run, --force (after upgrades), --with-rm, --prefix=DIR. Packagers: rtrash completions bash|zsh|fish, rtrash man, or rtrash setup --prefix=/usr.

MSRV 1.77. Default cargo install is a normal dynamically linked Linux binary. Tip of main: cargo install --git https://github.com/HaoZeke/rtrash.

Python#

pip install rtrash
python -c "import rtrash; print(rtrash.version())"

Linux x8664 wheels for CPython 3.10–3.14. Dev checkout: pip install maturin && maturin develop --features python.

Shortest CLI path#

echo data > scratch.txt
rtrash scratch.txt          # put (rm-shaped)
rtrash list
rtrash restore scratch.txt
rtrash scratch.txt
rtrash empty --trash-dir="$XDG_DATA_HOME/Trash"   # pin in scripts/tests

Shortest Python path (replace permanent delete)#

import os
from pathlib import Path
import rtrash

# Isolate trash in tests/scripts:
# os.environ["XDG_DATA_HOME"] = "/tmp/my-xdg"

p = Path("scratch.txt")
p.write_text("data")
rtrash.unlink(p)            # was: p.unlink() / os.remove(p)
assert not p.exists()
rtrash.restore_path(p)      # recover
assert p.read_text() == "data"

# directories (was shutil.rmtree):
# rtrash.rmtree("build/")

Next#

Interactive restore (first-class)#

On a TTY, rtrash restore opens the ratatui restore browser (filter /, navigate, Enter restore, multi-session until q). This is intentional product UX. Automation: --plain or a piped index.

rtrash a.txt b.txt
rtrash restore              # TUI on TTY
rtrash restore --cwd-only
rtrash restore --plain

Changelog#

Release notes: CHANGELOG.md. Unreleased fragments: docs/newsfragments/ (towncrier). See the repository README for prek / cog / release lockstep.