trash-cli — Terminal Trash (Safer Than rm) Safer Delete VPS
On servers, rm is fast—and unforgiving. trash-cli gives you a safety net by moving files to a Trash location (XDG / FreeDesktop Trash spec), keeping metadata like original path and deletion time so you can list and restore what you removed.
- Before editing/deleting critical files (
wp-config.php,.htaccess) - When cleaning WordPress logs/cache/uploads but you still want an “undo”
- In maintenance workflows where mistakes are expensive
Trash is still disk usage. If you trash large backups/media and never prune, your disk can fill up.
Prerequisites
- Ubuntu/Debian (or similar Linux VPS)
- SSH access
- Common WordPress paths (examples):
/var/www/html/→ WP root/var/www/html/wp-content/uploads/→ Media/home/backups/→ Backups
Install & Verify
- Debian/Ubuntu (APT)
- User install (pipx)
- User install (pip)
sudo apt update
sudo apt install -y trash-cli
pipx install trash-cli
If commands aren’t found, ensure ~/.local/bin is in your PATH.
pip install --user trash-cli
Verify:
trash --version || trash-put --version
How It Works
trash-cli follows the desktop Trash spec (XDG/FreeDesktop). In practice:
- “Deleting” becomes move to Trash
- You can audit what you trashed
- You can restore items to their original location
- You can prune Trash by age
Where is the Trash stored?
By default (per spec), the user Trash is typically:
echo ~/.local/share/Trash
You’ll usually see subfolders like files/ and info/.
Trash helps you recover from mistakes, but it’s not a real backup strategy. Use snapshots/backups for long-term safety.
Command Map
# Safer delete (move to Trash)
trash [FILES...] # often same as: trash-put [FILES...]
# Inspect
trash-list # list trashed items (original path + deletion date)
# Restore
trash-restore # interactive restore selection
trash-restore --overwrite # overwrite destination if needed
# Prune
trash-empty [DAYS] # empty all, or only items older than DAYS
# Permanently remove from Trash by pattern
trash-rm 'GLOB' # delete matching trashed items permanently
trash vs trash-putOn many systems, trash is a convenient wrapper/synonym for trash-put. If trash isn’t available, use trash-put.
Quick Decision Guide
| Goal | Best Command |
|---|---|
| -- | |
| Safer delete (keep an undo path) | trash file_or_dir |
| See what’s currently in Trash | trash-list |
| Restore something you removed | trash-restore |
| Restore even if file exists already | trash-restore --overwrite |
| Keep Trash under control automatically | trash-empty 30 |
| Permanently purge only certain trashed files | trash-rm '*.sql' |
Most Useful Moves (Ratings)
| Move | ⭐ Rating | Why It Matters |
|---|---|---|
| -: | -- | |
Use trash instead of rm for risky deletes | ⭐⭐⭐⭐⭐ | Gives you an undo path on production-like systems |
trash-restore | ⭐⭐⭐⭐⭐ | Brings back files without guesswork (interactive selection) |
trash-empty N | ⭐⭐⭐⭐ | Simple retention policy (great with cron) |
trash-list | ⭐⭐⭐⭐ | Fast audit trail of what you deleted |
trash-rm | ⭐⭐⭐ | Targeted permanent purge (useful, but less frequent) |
Best Practices
- Prefer
trashfor anything you might want back. - Set a retention policy (example: keep 30 days).
- Quote globs for
trash-rmso your shell doesn’t expand them early. - Avoid “blind” cleanup in production paths—always inspect first (
trash-list,ls,du -sh).
rm to trashThey are not identical in behavior and expectations (especially in scripts). If you must, use a safer wrapper that warns you rather than silently changing semantics.
Add a daily retention job (cron)
# Purge items older than 30 days, daily
(crontab -l 2>/dev/null; echo "@daily $(command -v trash-empty) 30") | crontab -
Troubleshooting
| Problem | Likely Cause | Fix |
|---|---|---|
| -- | - | - |
trash: command not found | Not installed or PATH missing | Install via APT/pipx/pip; ensure ~/.local/bin is in PATH |
| Can’t restore (name collision) | File already exists at destination | Use trash-restore --overwrite |
| “Where did my files go?” | Looking in wrong location | Check ~/.local/share/Trash (user Trash) |
| Disk still full after “deleting” | Trash not pruned | Run trash-empty (or trash-empty 30) |
trash-rm deletes nothing | Shell expanded glob before command | Quote pattern: trash-rm '*.log' |
Cheat Sheet
# Safe delete
trash foo.txt
trash dir/
# Audit
trash-list
# Restore
trash-restore
trash-restore --overwrite
# Retention / prune
trash-empty # empty all trash
trash-empty 30 # empty items older than 30 days
trash-rm '*.sql' # permanently purge matching trashed items
# Trash location (typical)
echo ~/.local/share/Trash
Worked Examples (Max 15)
WordPress root is /var/www/html.
Safely delete a WordPress debug log
trash /var/www/html/wp-content/debug.log
Safely move old Nginx logs to Trash
trash /var/log/nginx/*.log
List trashed items (page through)
trash-list | less
Restore a mistakenly deleted wp-config.php
trash-restore
Restore and overwrite an existing placeholder
trash-restore --overwrite
Empty items older than 7 days
trash-empty 7
Empty Trash completely (cleanup event)
trash-empty
Permanently remove only .sql dumps from Trash
trash-rm '*.sql'
Automate 30-day retention (cron)
(crontab -l 2>/dev/null; echo "@daily $(command -v trash-empty) 30") | crontab -
Trash multiple paths including directories
trash /home/backups/*.tar.gz /var/www/html/wp-content/cache
Confirm Trash location
echo ~/.local/share/Trash
Find a trashed upload quickly (ripgrep)
trash-list | rg -n 'uploads/.*\.jpg$'
Dry-review before permanent purge
trash-list | grep '\.log$'
(Then decide whether to run trash-rm '*.log'.)
Simple cleanup ritual
trash /home/backups/*.old && trash-empty 14
One-liner: find an entry, feed index into restore (advanced)
idx=$(trash-list | nl -ba | grep 'wp-content/uploads/logo' | awk '{print $1; exit}')
trash-restore <<< "$idx"
This relies on interactive restore behavior and the list ordering. Use it only if you understand what it’s doing.
Mini Quiz
- Which command moves files to Trash, and which command lists what’s inside?
- How do you restore a file when the destination already exists?
- What does
trash-empty 30do? - Where is the home Trash directory typically stored?
- Why is aliasing
rmtotrashdiscouraged?