Safer wrappers for rm and cp with trash-first behavior and directory-scope controls.
- Safe deletion: Moves files to system trash instead of permanent deletion
- GNU-like interface: Supports familiar
rm/cpflags with a focused subset - Execution control: Allows operations in current directory tree and optionally in additional directories via config
rm [OPTIONS] <PATH>...-dAllow removing empty directories-fForce removal, ignore non-existent files-rRemove directories recursively
# Remove an empty directory
rm -d empty_dir
# Remove a directory and its contents recursively
rm -r dir file.txt
# Force removal, ignore if files don't exist
rm -f non_existent.txt existing.txt
The rm command (from safecmd package) requires a configuration file at ~/.config/safecmd/config.toml to specify additional allowed directories. The file is automatically created on first run.
You can also start from config.example.toml in this repository.
[additional_allowed_directories]
paths = [
"/home/user/shared",
"/Users/yourname/Documents",
]
[notify]
macos_notify = false
SafeCmd supports several environment variables for configuration and testing:
- Purpose: Override the default configuration file location
- Default:
~/.config/safecmd/config.toml - Example:
SAFECMD_CONFIG_PATH=/custom/path/config.toml rm file.txt
- Purpose: Force-disable explicit test mode
- Effect: Ignores
SAFECMD_TEST_MODE=1and keeps normal scope restrictions - Example:
SAFECMD_DISABLE_TEST_MODE=1 SAFECMD_TEST_MODE=1 rm file.txt
- Purpose: Explicitly enable allow-all mode for tests only
- Effect: Only
SAFECMD_TEST_MODE=1enables allow-all (/) scope - Example:
SAFECMD_TEST_MODE=1 cargo test
CARGO_MANIFEST_DIR and CARGO are not used for automatic test mode detection.
The tables below summarize implemented behavior in safecmd versus GNU rm and GNU cp.
| Flag | safecmd rm behavior |
GNU rm behavior |
Notes |
|---|---|---|---|
-d |
Removes only empty directories by moving them to trash | Removes empty directories permanently | Same condition, different deletion target (trash vs permanent) |
-f |
Ignores missing paths and suppresses that error | Ignores missing paths and suppresses prompts/errors | Similar for missing files; no interactive prompt mode in safecmd |
-r |
Recursively removes directories by moving them to trash | Recursively removes directories permanently | Same recursion intent, different deletion target |
-R |
Alias of -r |
Alias of -r |
Equivalent in both |
Unsupported (for example -i, -I, --one-file-system) |
Not available | Available depending on flag | safecmd rm intentionally supports a smaller safe subset |
| Flag | safecmd cp behavior |
GNU cp behavior |
Notes |
|---|---|---|---|
-r |
Enables recursive directory copy | Enables recursive directory copy | Recursion enabled |
-R |
Alias of -r |
Alias of recursive copy | Recursion enabled |
--recursive |
Enables recursive directory copy | Enables recursive directory copy | Recursion enabled |
-n |
Skips overwrite when destination is an existing regular file | --no-clobber: does not overwrite existing files |
safecmd cp keeps type-conflict errors (for example file-to-directory) |
| No recursive flag (directory source) | Fails with omitting directory |
Fails with -r not specified; omitting directory |
Same outcome; wording differs |
| Overwrite existing target | Moves existing target to trash, then copies | Overwrites destination directly | safecmd cp adds a trash-first safety step |
Unsupported (for example -a, -p, --preserve) |
Not available | Available depending on flag | safecmd cp currently supports a focused subset |