spreen-clean — the falcon's stoop, then the preen — deletes files in a directory tree matching a glob pattern, dry run first.
It ships as a RubyGems gem and a PyPI library, both installing the same file-clean CLI.
The icon tells the story: the origami falcon (隼 /hayabusa/) mid-sweep across the malachite stone, scattered files dissolving ahead of its dive and a polished gleam left in its wake — the workspace, settled.
The full legend behind the spreen name is told in spreen-wiki's README.
$ file-clean '*.log' --dirname ./tmp
Target dirname is /home/hayat01sh1da/workspace/tmp
========== [DRY RUN] Total File Count to Clean: 2 ==========
========== [DRY RUN] Start Cleaning *.log ==========
========== [DRY RUN] Cleaning ./tmp/app.log ==========
========== [DRY RUN] Cleaning ./tmp/jobs/worker.log ==========
========== [DRY RUN] Cleaned *.log ==========
========== [DRY RUN] Total Cleaned File Count: 2 ==========Part of the spreen-* toolchain (spreen-wiki, spreen-pr, spreen-tracks, spreen-clean): tools that take something scattered and return it settled.
The tool is opinionated about safety: every run is a dry run until you say otherwise.
| Mode | Meaning | Filesystem |
|---|---|---|
d (default) |
Dry run | Prints every file that would be removed; nothing is touched. |
e |
Execution | Deletes every printed file. This cannot be undone. |
Any other mode fails with a clear error instead of guessing.
Two more guardrails back the dry-run default:
- Filesystem roots are refused. A dirname that resolves to
/(or a drive root likeC:\) fails with a clear error before anything is scanned, so a strayfile-cleancan never sweep an entire drive. - Bulk deletions ask first. When the execution mode matches more than 100 files, the CLI shows the count and asks for an explicit
ybefore deleting; pass--yesto skip the prompt in scripts.
Install from either ecosystem — the CLI is identical:
$ gem install spreen-clean$ pipx install spreen-clean(pip install spreen-clean works too if you prefer managing the environment yourself.)
$ file-clean [PATTERN] [options]PATTERNis the dirname or filename glob to clean; with noPATTERN, everything under the target directory matches (*).--dirname DIRsets the directory tree to clean (default: the current directory); the pattern matches recursively beneath it.--mode d|epicks the operation mode — dry run by default; passeto actually delete what the dry run printed:
$ file-clean '*.log' --dirname ./tmp --mode e
Target dirname is /home/hayat01sh1da/workspace/tmp
========== [EXECUTION] Total File Count to Clean: 2 ==========
========== [EXECUTION] Start Cleaning *.log ==========
========== [EXECUTION] Cleaning ./tmp/app.log ==========
========== [EXECUTION] Cleaning ./tmp/jobs/worker.log ==========
========== [EXECUTION] Cleaned *.log ==========
========== [EXECUTION] Total Cleaned File Count: 2 ==========--yesskips the bulk-delete confirmation that the execution mode raises above 100 matches — for scripted use.--versionprints the version;--helpprints the usage.
Both packages also expose the logic as a library — see the per-language READMEs below.
- Common environment: WSL (Ubuntu 25.10)
- Ruby README / Ruby sources
- Python README / Python sources