Modern Replacements for find

Replace find with fd, bfs or fselect: regex search with smart defaults, a breadth-first drop-in, or SQL-like file queries.

Updated

short verdict

Pick fd for everyday interactive searches: `fd PATTERN` replaces `find -iname '*PATTERN*'` and skips hidden and gitignored files. Pick bfs if you have existing scripts and want find's predicates unchanged. Pick fselect when you need to filter on metadata such as EXIF, MP3 tags or hashes, or aggregate results.

find matches files by name and attributes, but its expression syntax is verbose and it walks directories depth-first with no awareness of ignore files. The three tools here take different routes: fd shortens the syntax and changes the defaults, bfs keeps find's syntax and changes traversal order and error handling, and fselect replaces the expression language with SQL-like queries.

this page is for

  • Developers who search project trees and want ignore files respected
  • Admins with find scripts who want a compatible binary
  • Anyone querying files by size, dates, tags or hashes
#1

fd

★ 44.9kRust
details

A find replacement with regex patterns, smart case and .gitignore support, so a plain `fd PATTERN` covers most name searches.

best for

  • Interactive searches in code repositories
  • Running a command on every match with -x or -X

strengths

  • `fd PATTERN` replaces `find -iname '*PATTERN*'`
  • Parallelized directory traversal
  • Smart case: case-insensitive until the pattern has an uppercase letter
  • `-x` runs a command per result in parallel, `-X` batches; placeholders include `{}`, `{.}` and `{/}`

weaknesses

  • Hides dotfiles and gitignored paths by default; you need `-H` and `-I` to match find's output
  • Patterns are regex by default; exact filename globs need `-g`
  • Uses its own syntax rather than find's predicates, so existing find scripts need rewriting
#2

bfs

★ 1.3k
details

A breadth-first reimplementation of find that stays compatible with POSIX, GNU and BSD find, so existing expressions keep working.

best for

  • Scripts and habits built on find predicates
  • Searching large trees where matches sit near the top

strengths

  • Supports the same predicates, actions and expressions as standard find
  • Breadth-first traversal reaches shallow matches before descending into deep subtrees
  • Typo correction suggestions and static analysis warnings for suspect expressions
  • Extensions `-exclude` for skipping subtrees and `-nohidden` for ignoring hidden files

weaknesses

  • Keeps find's long expression syntax for simple name searches
  • Regex matching by default, smart case and .gitignore handling are not documented by the project
  • Packaging is documented for Homebrew, APT and DNF only
#3

fselect

★ 4.5k
details

Queries the filesystem with SQL-like statements, which suits metadata-heavy searches that are awkward to express in find.

best for

  • Filtering by image dimensions, EXIF, MP3 tags, MIME type or hashes
  • Reports with COUNT, SUM, AVG, MIN or MAX over results

strengths

  • Queries like `fselect size, path from /home/user where name = '*.cfg' or name = '*.tmp'`
  • Searches inside archives and reads image, MP3, hash, MIME and POSIX attribute data
  • Outputs CSV, JSON or HTML, and has an interactive mode for building queries
  • Date filters accept 'today', 'yesterday' and 'last fri'; can respect .gitignore, .hgignore and .dockerignore

weaknesses

  • The SQL-like syntax shares nothing with find, so no script or muscle memory carries over
  • A simple name lookup takes more typing than `fd PATTERN` or `find -name`
  • No find-compatible flags are documented

What changes compared to find

The tools differ from find in syntax, defaults and output, not just speed.

  • fd: `fd PATTERN` replaces `find -iname '*PATTERN*'`, with regex matching and `-g` for globs
  • fd: hidden files and .gitignore matches are skipped unless you pass `-H` or `-I`
  • fd: output is colored by file type, and `-x`/`-X` replace find's `-exec` with parallel or batched runs
  • bfs: walks breadth-first instead of depth-first, so shallow matches appear sooner
  • bfs: accepts arguments in flexible order and suggests corrections for typos
  • fselect: you write `select ... from ... where ...` queries and can emit CSV, JSON or HTML

Switching from find

Migration effort depends on the tool.

  • bfs: documented as compatible with POSIX, GNU and BSD find and as a drop-in for existing scripts
  • bfs: add `-exclude` or `-nohidden` where you used long `-prune` style expressions
  • fd: swap `find -iname '*foo*'` for `fd foo`; replace `-exec` with `-x`, or `-X` for one batched call
  • fselect: rewrite each search as a query; no flag mapping from find is documented

When not to use these

  • You need a binary that is guaranteed to exist on every minimal server or container; find ships with the system, these do not
  • Your script relies on find's exact output, including hidden and ignored files, and you cannot retest it

FAQ

Is fd a drop-in replacement for find in scripts?
No. fd uses its own syntax (`fd PATTERN`, `-x`, `-X`) and skips hidden and gitignored files by default. Compatibility with find's flags is not documented, so existing scripts need rewriting.
Which tool can run existing find scripts unchanged?
bfs. The project describes it as compatible with POSIX, GNU and BSD find, supporting the same predicates, actions and expressions, and as a drop-in replacement for existing scripts.
Does any of these respect .gitignore?
fd does automatically, and `-I` turns that off. fselect can respect .gitignore, .hgignore and .dockerignore. bfs does not document gitignore support, but `-nohidden` skips hidden files.
Which one is best for searching by file metadata?
fselect. It can filter on image width, height and EXIF, MP3 genre, bitrate and year, file hashes, MIME types and POSIX attributes, and it can aggregate with COUNT, SUM, AVG, MIN and MAX.

related