The standard Unix find utility is one of the most versatile command-line tools in system administration. However, find traverses directory trees strictly using a depth-first search (DFS) algorithm. When searching large file trees, monorepos, or nested network file systems, depth-first traversal dives deeply into the bottom of the first subdirectory branch before surfacing—often spending minutes exploring massive node_modules or build directories while the target file sits right in the top-level directory.
To overcome this architectural limitation, developer Tavian Barnes created bfs (Breadth-First Search). Built as a 100% flag-compatible alternative to GNU find, bfs visits shallow directories first, finding target files near the root orders of magnitude faster. Furthermore, bfs features colored terminal output, interactive error handling, and parallel directory iteration. This comprehensive tutorial walks you through installing bfs on Linux, understanding breadth-first traversal mechanics, and utilizing advanced search expressions.
Breadth-First (bfs) vs Depth-First (find): The Difference
To understand why bfs frequently outperforms standard find in interactive workflows, consider how directory trees are traversed:
- Depth-First Search (Standard
find): Traverses down to the deepest leaf node of directoryA/B/C/D/before examining directoryE/. If you are searching for a configuration file located in~/project/config.yaml, standardfindmay first crawl hundreds of thousands of files inside deep caches, cache directories, or vendor trees. - Breadth-First Search (
bfs): Traverses level-by-level. It inspects all files at depth 1, then all files at depth 2, and so forth. In typical interactive use, users are far more likely to search for files closer to their working directory root, allowingbfsto display matches almost instantaneously.
Step 1: Installing bfs on Linux
bfs is packaged natively across modern Linux distribution repositories and can also be installed as a precompiled standalone binary.
Method A: On Ubuntu and Debian Systems
Available natively in Debian 11/12 and Ubuntu 22.04 LTS or newer:
sudo apt update
sudo apt install -y bfs
Method B: On Fedora, RHEL, and CentOS Stream
Available in Fedora repositories and EPEL for Enterprise Linux:
sudo dnf install -y bfs
Method C: On Arch Linux
sudo pacman -S bfs
Method D: Building from Source (Latest Version)
If your distribution repository contains an older release, compiling bfs requires only a standard C compiler and make:
# Install build dependencies
sudo apt install -y git gcc make libonig-dev libcap-dev libacl1-dev
# Clone repository and compile
git clone https://github.com/tavianator/bfs.git
cd bfs
./configure
make -j$(nproc)
sudo make install
# Confirm installation
bfs --version
Step 2: Basic Syntax and Drop-In Compatibility with find
Because bfs mirrors GNU find flag syntax, any standard find command can be executed with bfs without modification:
# Standard file search by name
bfs . -name "*.conf"
# Case-insensitive name search
bfs /etc -iname "*nginx*"
# Search by file type (files only)
bfs ~/projects -type f -name "Dockerfile"
# Search by file type (directories only)
bfs ~ -type d -name ".git"
Unlike standard find, bfs automatically colorizes output based on your system’s LS_COLORS configuration, rendering executables, symlinks, archives, and directories in distinct hues for fast visual scanning.
Step 3: Shallow File Discovery with Early Exit
When searching for a single file or inspecting whether a file exists in a project, combining breadth-first traversal with the -exit action returns results with near-zero latency:
# Find the nearest .env file and stop immediately
bfs . -name ".env" -print -exit
While GNU find . -name ".env" -print -quit would still dive down into the deepest subdirectory branch first if it encountered a folder before the .env file, bfs checks the top level immediately and terminates instantly upon matching.
Step 4: Advanced Filtering Expressions in bfs
bfs supports the full spectrum of time, size, and permission predicates supported by modern Unix linkers and shells:
1. Searching by File Size
# Find all files larger than 100 Megabytes
bfs /var/log -type f -size +100M
# Find empty files or directories
bfs . -empty
2. Filtering by Modification and Access Times
# Files modified within the last 24 hours
bfs ~/documents -type f -mtime -1
# Files modified more than 30 days ago
bfs /tmp -type f -mtime +30
3. Filtering by Unix Permissions
# Find world-writable files (security audit)
bfs /var/www -type f -perm -o+w
# Find files with SUID bit set
bfs /usr/bin -type f -perm -4000
Step 5: Excluding Heavy Directories with -exclude
In standard find, pruning deep directories requires unwieldy syntax: -name node_modules -prune -o -print. bfs introduces an intuitive, human-friendly -exclude action that operates seamlessly:
# Search for TypeScript files, skipping node_modules and .git completely
bfs . -exclude -name node_modules -exclude -name .git -name "*.ts"
When bfs encounters an excluded directory name, it prunes the entire subtree without descending into it, conserving disk read cycles and CPU memory.
Step 6: Executing Batch Actions with -exec
Like find, bfs can pass matching paths directly to background commands or utilities:
# Compute SHA256 checksums for all ISO images
bfs /data/iso -name "*.iso" -exec sha256sum {} +
# Change file permissions on all shell scripts
bfs ~/scripts -name "*.sh" -exec chmod +x {} +
Using + at the end of the -exec expression aggregates multiple file paths into a single command invocation, avoiding the overhead of spawning a new subshell process for every single file.
Parallel Breadth-First Search (-j)
On modern multi-core systems with high-speed NVMe solid-state storage, bfs can parallelise directory traversal across multiple CPU threads using the -j flag:
# Run breadth-first search across all available CPU cores
bfs / -j$(nproc) -name "nginx.conf" 2>/dev/null
Multi-threaded traversal dramatically accelerates searches across massive filesystems containing millions of inodes.
bfs vs find Feature Comparison Table
| Feature | GNU find |
bfs |
|---|---|---|
| Traversal Algorithm | Depth-First Search (DFS) | Breadth-First Search (BFS) |
| Shallow File Speed | Slow (dives into deep branches first) | Fast (evaluates shallow levels first) |
| Colored Terminal Output | No (plain text only) | Yes (automatic LS_COLORS support) |
| Multi-Core Parallelism | No (single-threaded) | Yes (via -j <threads>) |
| Pruning Syntax | Complex (-prune -o ...) |
Intuitive (-exclude -name ...) |
| Flag Compatibility | POSIX / GNU Standard | 100% GNU find Compatible |
Troubleshooting Common bfs Queries
| Issue | Cause | Fix |
|---|---|---|
| “Permission denied” clutter | Attempting to read root/system files | Redirect stderr: bfs / -name "app.log" 2>/dev/null |
| Unexpected shell expansion error | Unquoted wildcard (e.g., bfs . -name *.txt) |
Always wrap wildcards in single or double quotes: bfs . -name "*.txt" |
| Out of memory on multi-billion inode trees | Queueing massive breadth layers | Limit maximum search depth using -maxdepth <N> (e.g., bfs . -maxdepth 5). |