kfind — fast, tiny file finder written in V
| .gitignore | ||
| kfind.v | ||
| LICENSE | ||
| project.v | ||
| README.md | ||
README.md
kfind — fast, tiny file finder in V
kfind is a tiny, dependency-free file finder written in V with extension, name filtering, and JSON/NDJSON output.
It walks a directory tree quickly, filters by extension and name, and prints a stable, sorted list of matches — perfect for scripting and sysadmin workflows.
Why admins love it
- Single static binary – drop it on any box and go.
- Deterministic output – sorted paths make diffs and pipelines reliable.
- Targeted scans – extension set + name query + optional depth cap = fast, focused searches.
- No surprises – doesn’t follow hidden files/dirs unless you ask it to; clear, readable code.
Install / Run
# Run directly
v run kfind.v [path] [flags]
# Build an optimized binary
v -prod -o kfind kfind.v
./kfind [path] [flags]
CLI
kfind <version>
-----------------------------------------------
Usage: kfind [options] [path]
Description: Fast file finder with extension and name filtering.
Options:
-e, --ext <string> Comma-separated list of extensions to include (e.g. "rs,zig,v")
-n, --name <string> Substring to match in file path/name
-i, --ignore-case Case-insensitive name matching
-H, --hidden Include hidden files and directories
-d, --max-depth <int> Maximum recursion depth (-1 = unlimited)
-J, --json Output JSON array (["/a","/b",...])
-N, --ndjson Output line-delimited JSON objects ({"path":"..."} per line)
-h, --help display this help and exit
--version output version information and exit
Examples
# Everything under current directory
kfind
# Only code-ish files
kfind . --ext=rs,zig,v,go,py
# Match by name (case-insensitive)
kfind /var/log --name error --ignore-case
# Limit recursion for speed
kfind /srv --ext=png,jpg --max-depth=2
# Include hidden entries
kfind --hidden --name .env
# JSON array for programmatic use
kfind . --ext=rs,zig,v -J | jq length
# NDJSON, perfect for big streams
kfind /var/log -n error -N | jq -r '.path' | xargs tail -n1
What makes kfind fast — the “k-find” algorithm
kfind uses a pruned depth-first search (DFS) with constant-time extension checks and optional query filtering:
- Normalize and pre-index extensions
--ext=jpg,png→{'jpg': true, 'png': true}- Membership test is O(1) per file.
- Pruned DFS with an optional depth cap
max-depth = -1→ unlimited.- If
max-depth >= 0, recursion stops oncedepth > max-depth. - Hidden files/dirs are skipped early unless
--hiddenis set, reducing work.
- Cheap, streaming filters
- For each file, only compute
file_ext()and a substring match for--name. - If
--ignore-case, both strings are lower-cased once; no regex backtracking.
- For each file, only compute
- Stable, minimal memory usage
- DFS keeps one directory’s listing at a time; memory ~ O(matches + depth).
- Final output is sorted once at the end for reproducibility in scripts.
Complexity:
- Let
Nbe total directory entries visited. Time is O(N) with small constants. - Filtering cost is linear in filename lengths; extension checks are constant-time.
- Memory: O(M + D) where
Mis number of matches,Dis max recursion depth.
Pseudocode
ext_set = hashset(normalize(--ext))
dfs(path, depth):
if max_depth >= 0 and depth > max_depth: return
for entry in ls(path):
if !hidden && is_hidden(entry): continue
full = join(path, entry)
if is_dir(full): dfs(full, depth + 1)
else if (ext_set empty || file_ext(full) in ext_set) and name_matches(full):
emit(full)
sort(results); print(results)
Design choices
- No nested functions (V style) → helpers live at top level.
- Explicit closure captures for safety:
fn [query, case_insensitive] (f string) bool { ... }. - Immutability-first with copy-on-write where needed:
mut matches := files.clone(). - Clear failure modes: unreadable directories print a warning and the walk continues.
- No symlink following by default (can be added later as a flag).
Scripting tips
- Count matches:
kfind --ext=log | wc -l - Feed into other tools:
kfind /var/log -n error | xargs tail -n1 - Save snapshots for diffing:
kfind /srv/www --ext=html,css,js > listing.txt
Roadmap (nice-to-haves)
--follow-symlinks- Regex mode:
--name-regex - Parallel walk (worker pool) for massive trees
JSON/NDJSON output for machine users✅ (added)
License
This project is licensed under the European Union Public Licence v. 1.2. See the LICENSE file for details.