rtrash shares the trash with trash-cli, gtrash, GNOME’s gio trash and the desktop file managers built on it. This page records what matches and what differs. The Linux rows come from live runs against trash-cli 0.26.9.29, gtrash and gio 2.84 on one shared trash. CI repeats the cross-restore rows on every push with scripts/interop-smoke.sh, in all sixteen pairings.

Shared trash#

Behaviour

rtrash

trash-cli

gtrash

gio trash

Home trash $XDG_DATA_HOME/Trash

yes

yes

yes

yes

Volume trash .Trash/$uid and .Trash-$uid

yes

yes

yes

yes

Reads entries the others wrote

yes

yes

yes

yes

Names with spaces, % and Unicode

yes

yes

yes

yes

Second item with the same name

name_1

name_1

name.2

name.2

Restores items the others trashed

yes

yes

yes

yes

Removes and empties rtrash items

yes

yes

yes

yes

Each tool reads the others’ duplicate names, so the spelling only shows in files/. gio lists and restores rtrash items (gio trash --list, gio trash --restore trash:///NAME), and rtrash restores gio items. GLib caveat: gio 2.80.0 with gvfs 1.54.4 (Ubuntu 24.04) restores any non-ASCII name escaped, so x é comes back as x \xc3\xa9, even for an item gio trashed itself, under a UTF-8 locale; x 100% comes back intact. gio 2.84 (Debian 13) and gio 2.88.0 (Ubuntu 26.04) restore both intact. The interop smoke test probes x é, x 100% and x 100% é with gio alone: when x 100% fails it leaves gio out, and when a non-ASCII probe fails the run fails, so on GLib 2.80 set RTRASH_INTEROP_NO_GIO=1. No upstream GLib or gvfs issue turned up in a search. The likely cause: the original gio trash --restore code (725984f) reads trash::orig-path with g_file_info_get_attribute_as_string(), which escapes non-ASCII bytes for display. The GLib documentation for that function now uses trash::orig-path as its example of an attribute to read as a byte string instead, which fits a fix between 2.80 and 2.84.

trash-cli command lines#

Linked as trash-put, trash-list, trash-empty, trash-restore and trash-rm, rtrash takes a trash-cli command line as is.

trash-cli

rtrash under the trash-* name

--trash-dir DIR (two words)

same; --trash-dir=DIR works too

--print-completion bash or zsh

same; tcsh has no script (exit 2)

zsh matcher-list (trash-cli #363)

restore and rm complete trashed paths (and names) through compadd, so matcher-list applies; all six scripts complete them

trash-put exit 74 on a failure

same

trash-list --volumes

same

trash-list --trash-dirs

same

trash-list --all-users

same rows; rtrash list adds an owner column

trash-list --size

same SIZE PATH rows, size in bytes

trash-list --files

same DATE PATH -> FILE rows

trash-list stderr per bad record

same Parse Error: and [Errno N] lines; a hint counts the rest

trash-empty DAYS, -f

same; DAYS also takes an age such as 2h

trash-empty -i

same prompt, then empties

trash-empty --all-users

same

unscoped trash-empty (no DAYS)

asks or refuses unless every item came from the latest put; --all skips the guard; on Windows too, by the last-put record

trash-restore (current dir)

same scope and “No files trashed” message

trash-restore PATH

same: the item at PATH and items from under it

trash-restore --sort date/path/none

same

trash-restore --overwrite

same

trash-rm PATTERN

same; no match exits 0

On a terminal, trash-restore and trash-empty open the rtrash browser; --plain keeps the numbered prompt. rtrash restore with no PATH offers every item, and a PATH must match exactly; only the trash-restore name narrows to the current directory.

Beyond trash-cli and gtrash#

These exist only in rtrash: rm(1) flags on put, undo of the last put run, size budgets (empty --max-size), du and reap, --json on every listing, and the restore conflict policies (--conflict=rename|skip), which restore --dry-run previews. A read-only home trash fails put up front with one clear reason, since it has no fallback; trash-cli fails each item with a bare error.

trashy patterns#

trashy takes its patterns as plain arguments to restore and empty, read as regular expressions unless -m (--match) names another kind. In rtrash a flag names the kind:

trashy

rtrash

trashy restore PATTERN

rtrash restore --regex=PATTERN

trashy restore --match=glob P

rtrash restore --glob=P

trashy restore -m substring P

rtrash restore -m substring P

trashy restore -m exact P

rtrash restore -m exact P

trashy empty PATTERN

rtrash rm --regex PATTERN

trashy empty --match=glob P

rtrash rm P (globs are the default)

trashy empty -m substring P

rtrash rm -m substring P

trashy empty -m exact P

rtrash rm -m exact P

A regex for rm searches the whole original path, on the FreeDesktop, Finder and Windows trashes alike. One that matches every path (such as .*) needs --force, as * does. restore -m and rm -m with substring or exact read the text against the original path as trashy does; only the default differs (glob here, regex in trashy).

macOS#

Behaviour

rtrash

Finder

Plain rtrash put

Finder Trash ~/.Trash, through Finder

yes

Put Back after a plain put

yes; Finder records it

yes

Plain list, restore, empty

Finder Trash, by Put Back location

yes

list --glob/--regex/--name/--cwd-only

same matchers as restore, on the Finder Trash and Windows too

no

put --dry-run

every check, nothing moves (Windows too)

no

bare list PATTERN, restore '*.log'

substring or glob, like gtrash find

no

list --format=TEMPLATE

fields {date} {path} {name} {size} …, raw bytes, \0 rows; Finder and Windows too

no

empty -v

one removed ORIGINAL line per item, every backend

no

WSL: /mnt/c files to the Recycle Bin

opt-in, RTRASH_WSL_RECYCLE=1

no

WSL: list, restore and delete Recycle Bin items

rtrash wsl list [--json|--format=T] [MATCH], restore PATH (completes recycled paths), rm MATCH (completes recycled paths and names), empty [DAYS] (guarded)

no

restore --batch=ID (or last)

one put run as a unit (same as undo)

no

FreeDesktop home trash

RTRASH_MACOS_TRASH=freedesktop, macos.trash or a --trash-dir pin

no

undo, status, trash-stats, restore browser

Finder Trash; undo from a put-run log

n/a

Symbolic links

move in as themselves, without Put Back

follows

Volume trash /Volumes/X/.Trashes/UID

plain commands, as Finder; put there for items on the drive

yes

Permanent delete (rm PATTERN)

Finder trashes, by Put Back path or name

no

Permanent delete of one put run (rm --batch=ID, or last)

Finder trashes, by the put log; Windows: last only

no

Composed vs decomposed names (NFC/NFD)

match alike in list, restore, rm and undo; restore –name/–glob/–regex on every trash

n/a

Age filters count from the move into the trash and size filters from disk usage; restore takes --name, --glob, --regex, --latest and --to. trash-stats --total and --history read a total and history per Finder trash kept under $XDG_STATE_HOME/rtrash/finder-totals: put, rm, empty, restore and undo carry a current total, inodes included, by the items they move; a change made outside rtrash marks the total stale until --measure. empty --max-size and --prune trim the Finder trashes together, by disk usage. RTRASH_MAX_SIZE and policy.max_size trim each Finder trash a put used, sparing what that put moved. empty --until-free and reap --purge-trash empty the oldest Finder items first on a short file system, since a put there goes to the Finder Trash. empty --dangling needs FreeDesktop records, so on the Finder Trash it is refused with a hint. CI runs plain put, list, restore and empty on a real macOS runner against Finder.