`bfs` is a variant of the UNIX `find` command that operates [**breadth-first**](https://en.wikipedia.org/wiki/Breadth-first_search) rather than [**depth-first**](https://en.wikipedia.org/wiki/Depth-first_search).
It is otherwise compatible with many versions of `find`, including
[ **[POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html)** ]
[ **[GNU](https://www.gnu.org/software/findutils/)** ]
[ **[FreeBSD](https://www.freebsd.org/cgi/man.cgi?find(1))** ]
[ **[OpenBSD](https://man.openbsd.org/find.1)** ]
[ **[NetBSD](https://man.netbsd.org/find.1)** ]
[ **[macOS](https://ss64.com/osx/find.html)** ]
If you're not familiar with `find`, the [GNU find manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) provides a good introduction.
Features
--------
bfs
operates breadth-first, which typically finds the file(s) you're looking for faster.
Imagine the following directory tree:
haystack
├── deep
│ └── 1
│ └── 2
│ └── 3
│ └── 4
│ └── ...
└── shallow
└── needle
`find` will explore the entire `deep` directory tree before it ever gets to the `shallow` one that contains what you're looking for.
$ find haystack
haystack
haystack/deep
haystack/deep/1
haystack/deep/1/2
haystack/deep/1/2/3
haystack/deep/1/2/3/4
...
haystack/shallow
haystack/shallow/needle
On the other hand, `bfs` lists files from shallowest to deepest, so you never have to wait for it to explore an entire unrelated subtree.
$ bfs haystack
haystack
haystack/deep
haystack/shallow
haystack/deep/1
haystack/shallow/needle
haystack/deep/1/2
haystack/deep/1/2/3
haystack/deep/1/2/3/4
...
bfs
tries to be easier to use than find
, while remaining compatible.
For example, `bfs` is less picky about where you put its arguments:
$ bfs -L -name 'needle' haystack │ $ find -L -name 'needle' haystack
haystack/needle │ find: paths must precede expression: haystack
│
$ bfs haystack -L -name 'needle' │ $ find haystack -L -name 'needle'
haystack/needle │ find: unknown predicate `-L'
│
$ bfs -L haystack -name 'needle' │ $ find -L haystack -name 'needle'
haystack/needle │ haystack/needle
bfs
gives helpful errors and warnings.
For example, `bfs` will detect and suggest corrections for typos:
$ bfs -nam needle
bfs: error: bfs -nam needle
bfs: error: ~~~~
bfs: error: Unknown argument; did you mean -name?
`bfs` also includes a powerful static analysis to identify likely mistakes:
$ bfs -print -name 'needle'
bfs: warning: bfs -print -name needle
bfs: warning: ~~~~~~~~~~~~
bfs: warning: The result of this expression is ignored.
bfs
adds some options that make common tasks easier.
### `-exclude`
The `-exclude` operator skips an entire subtree whenever an expression matches.
For example, `-exclude -name .git` will exclude any files or directories named `.git` from the search results.
`-exclude` is easier to use than the standard `-prune` action; compare
bfs -name config -exclude -name .git
to the equivalent
find ! \( -name .git -prune \) -name config
Unlike `-prune`, `-exclude` even works in combination with `-depth`/`-delete`.
---
### `-hidden`/`-nohidden`
`-hidden` matches "hidden" files (dotfiles).
`bfs -hidden` is effectively shorthand for
find \( -name '.*' -not -name . -not -name .. \)
`-nohidden` is equivalent to `-exclude -hidden`.
---
### `-unique`
This option ensures that `bfs` only visits each file once, even if it's reachable through multiple hard or symbolic links.
It's particularly useful when following symbolic links (`-L`).
---
### `-color`/`-nocolor`
When printing to a terminal, `bfs` automatically colors paths like GNU `ls`, according to the `LS_COLORS` environment variable.
The `-color` and `-nocolor` options override the automatic behavior, which may be handy when you want to preserve colors through a pipe:
bfs -color | less -R
If the [`NO_COLOR`](https://no-color.org/) environment variable is set, colors will be disabled by default.
Installation
------------
bfs
may already be packaged for your operating system.
Alpine Linux
# apk add bfs
Arch Linux
Available in the AUR
Debian/Ubuntu
# apt install bfs
NixOS
# nix-env -i bfs
Void Linux
# xbps-install -S bfs
FreeBSD
# pkg install bfs
MacPorts
# port install bfs
Homebrew
$ brew install tavianator/tap/bfs
To build bfs
from source, you may need to install some dependencies.
The only absolute requirements for building `bfs` are a C compiler, [GNU make](https://www.gnu.org/software/make/), and [Bash](https://www.gnu.org/software/bash/).
These are installed by default on many systems, and easy to install on most others.
Refer to your operating system's documentation on building software.
`bfs` also depends on some system libraries for some of its features.
Here's how to install them on some common platforms:
Alpine Linux
# apk add acl{,-dev} attr{,-dev} libcap{,-dev} oniguruma-dev
Arch Linux
# pacman -S acl attr libcap oniguruma
Debian/Ubuntu
# apt install acl libacl1-dev attr libattr1-dev libcap2-bin libcap-dev libonig-dev
Fedora
# dnf install libacl-devel libattr-devel libcap-devel oniguruma-devel
NixOS
# nix-env -i acl attr libcap oniguruma
Void Linux
# xbps-install -S acl-{devel,progs} attr-{devel,progs} libcap-{devel,progs} oniguruma-devel
FreeBSD
# pkg install oniguruma
MacPorts
# port install oniguruma6
Homebrew
$ brew install oniguruma
These dependencies are technically optional, though strongly recommended.
See the [build documentation](/docs/BUILDING.md#dependencies) for how to disable them.
Once you have the dependencies, you can build bfs
.
Download one of the [releases](https://github.com/tavianator/bfs/releases) or clone the [git repo](https://github.com/tavianator/bfs).
Then run
$ make
This will build the `bfs` binary in the current directory.
Run the test suite to make sure it works correctly:
$ make check
If you're interested in speed, you may want to build the release version instead:
$ make release
Finally, if you want to install it globally, run
# make install