diskhog
TUI that lists the largest files on disk and lets you delete the ones you pick — either to the trash, or for real — with each file's size and its share of total disk space shown right in the list.
$ diskhog / # scan the whole filesystem
$ diskhog ~/Downloads # or any directory
$ diskhog --top 200 /var # show more than the default 30
$ diskhog --max-cpu 60 /var # allow a bigger/smaller worker pool than the default 30%
$ diskhog --exclude node_modules ~/code # skip anything matching a glob (repeatable)
The directory is required — diskhog never picks a scan target for you.
Stays on the filesystem it started on — it won't wander into /proc,
/sys, other mounted disks, or network shares. Symlinks are skipped so they
can't be followed off the filesystem or double-count another file's size.
The walk itself is parallel (via the ignore
crate — the same walker ripgrep uses), capped by default to ~30% of
available cores so a scan doesn't try to claim the whole machine —
adjustable with --max-cpu <1-100> — with a live "N files scanned so far"
counter printed while it runs.
--exclude <PATTERN> (repeatable, e.g. --exclude node_modules --exclude '*.log') skips anything matching the glob — a plain name like
node_modules matches that directory anywhere under the scan root, same
as a .gitignore entry would. Handy for the things you already know are
big and already know you don't want to touch (build output, .git,
package caches).
Each row also shows how long ago the file was last modified — 3h,
12d, 2mo, 1y — so you're not guessing whether something huge is
live data or forgotten cruft before you decide to delete it.
Performance
A sample run on an Ubuntu desktop, finding the 30 largest files under /:
$ time sudo find / -type f -printf '%s %p\n' | sort -rn | head -30
...
real 0m12.125s
user 0m2.417s
sys 0m0.290s
$ time sudo diskhog /
...
real 0m0.994s
user 0m0.005s
sys 0m0.020s
diskhog finished about 12x faster than the find | sort | head approach —
the parallel walk and bounded top-N heap avoid both sorting every file in
the tree and holding the whole listing in memory at once.
du is the other common way people hunt for large files, so here's a
second sample — no root needed this time, 187,233 files / 8.8GB under
/usr, page cache already warm from repeated runs:
$ time du -ah /usr | sort -rh | head -30
...
real 0m1.473s
user 0m1.074s
sys 0m1.828s
$ time find /usr -type f -printf '%s %p\n' | sort -rn | head -30
...
real 0m0.338s
user 0m0.733s
sys 0m1.322s
$ time diskhog /usr
...
real 0m0.367s
user 0m0.142s
sys 0m0.951s
du -ah is the slowest of the three here — it computes a running total
for every directory and lists every file, which is more work than
either find or diskhog do. With the page cache already warm, find
and diskhog end up close to each other — the 12x gap above shows up on
a cold, uncached, whole-filesystem walk, where diskhog's parallel I/O
matters most; on a warm cache over a smaller tree, single-threaded find
can keep pace. du's extra per-directory accounting is the one place it
consistently loses no matter the cache state.
Deleting always asks, and always asks which way
Selecting a file and pressing Enter/d shows a confirmation dialog with
the exact path, size, and how long ago it was last modified, and two
ways to actually remove it:
t— move to the trash (via thetrashcrate, following the freedesktop.org trash spec on Linux), recoverable like anything else you deleted by hand. This does not free disk space — on the file's own filesystem it's a same-filesystem rename, so the data blocks stay allocated until the trash itself is emptied.p— permanently delete it (an actual unlink). Frees the space immediately; no way back.
Any other key cancels.
Install
- Cargo:
cargo install diskhog - Debian package: https://github.com/wabuntu/diskhog/tree/main/target/debian
- RPM package: https://github.com/wabuntu/diskhog/tree/main/target/release/rpmbuild/RPMS/x86_64
- Single binary: https://github.com/wabuntu/diskhog/tree/main/binaries
Usage
Keys:
↑/↓: move the selectionEnter/d: open the delete confirmation for the selected filet: move it to the trash (recoverable, space not freed)p: permanently delete it (frees space, no undo)- any other key: cancel the pending delete
q/Esc: quit
Flags:
--top <N>: how many of the largest files to show (default 30)--max-cpu <1-100>: cap the scan's worker threads to this percentage of available cores (default 30)--exclude <PATTERN>/-x <PATTERN>: skip paths matching this glob (repeatable — pass it more than once to exclude several patterns)