fd: A Simpler, Faster Alternative to find
What You'll Learn
- Escape find's complex syntax and search recursively with just
fd PATTERN - Solve the Ubuntu/Debian
fdfindgotcha (the command isn't calledfd) - Master the real-world patterns: extensions, types, gitignore handling,
-xexec
Quick Summary
- Everyday "where is that file?" →
fd PATTERN(fast, short, colorized) - Search even ignored files →
fd -H -I PATTERN - When you still need find → complex
-newerconditions,-printfformatting, POSIX-only boxes
Assumptions (target environment)
- OS: Ubuntu 22.04 / 24.04 (Debian family) as the primary target; adapt for other distros
- fd 8.x or later
What Is fd?
Conclusion: fd is a modern file search tool written in Rust. As a find alternative, it ships with short syntax, high speed, automatic .gitignore handling, and colorized output.
fd is a user-friendly alternative to find, developed at sharkdp/fd. It does not replace every feature of find, but for 90% of everyday file searches it is faster and shorter to write.
Key differences from find:
| Aspect | find | fd |
|---|---|---|
| Basic syntax | find . -name '*.txt' |
fd '\.txt$' / fd -e txt |
| Match style | exact by default (-name) |
substring regex |
| Case sensitivity | case-sensitive | smart case (ignored if lowercase) |
| Hidden files | searched | excluded by default (-H includes) |
.gitignore |
ignored | respected automatically (-I off) |
| Output | monochrome | colorized (by type) |
| Speed | baseline | parallel, fast |
How Do You Install fd?
Conclusion: On Ubuntu/Debian, install with
apt install fd-find— but the command is namedfdfind, notfd. The common fix is a symlink or alias to expose it asfd.
Install per distribution:
# Ubuntu / Debian sudo apt install fd-find # Fedora / RHEL family sudo dnf install fd-find # Arch Linux sudo pacman -S fd # macOS (Homebrew) brew install fd # From Rust's cargo cargo install fd-find
Ubuntu/Debian gotcha: the command is fdfind
Because of a name clash with another package (fdclone) on Debian, the binary is named fdfind instead of fd. Typing fd directly gives command not found.
To use it as fd, create a symlink in ~/.local/bin:
mkdir -p ~/.local/bin ln -s "$(which fdfind)" ~/.local/bin/fd
If ~/.local/bin is not on your PATH, add it to ~/.bashrc and reload:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc source ~/.bashrc
Verify the install and version:
fd --version
fd 9.0.0
What Are the Basics of fd?
Conclusion:
fd PATTERNsearches recursively below the current directory. The pattern is a substring regex, and you can give the search root as a second argument.
The minimal usage is just a fragment of the name you want:
fd readme
README.md docs/readme-ja.md src/readme.txt
Where find needs find . -iname '*readme*', fd readme is enough. Case is handled with smart case (case-insensitive if the pattern is all lowercase).
Specify the starting directory as the second argument:
# Search for config below src/ fd config src/
The pattern is interpreted as a regular expression, so dots and anchors work directly:
# Files ending in .log fd '\.log$'
fd with no arguments lists every file and directory below the current one (excluding .gitignored and hidden files). Use it instead of ls -R.
How Do You Filter by Extension or Type?
Conclusion: Filter by extension with
-e EXTand by kind with-t TYPE(f=file / d=directory / l=symlink / x=executable). Multiple values are OR'd together.
Filter by extension with -e (--extension); no dot needed:
# Find .jpg and .png (multiple flags = OR) fd -e jpg -e png
Filter by kind with -t (--type):
# Directories only fd -t d node_modules # Executable files only fd -t x # Empty files / directories fd -t empty
Common type values:
f… regular filed… directoryl… symlinkx… executablee… empty
Combine with a pattern to do ".rs files below src" in one shot:
fd -e rs main src/
How Do You Search Hidden or .gitignore'd Files?
Conclusion: By default fd excludes hidden files and anything in
.gitignore. Use-Hto include hidden files,-Ito disable ignore rules, and-u(unrestricted) to lift both at once.
fd's "helpful" behavior can get in your way — that is why a search for .env or node_modules/ comes up empty.
# Include hidden (dotfiles) fd -H '\.env' # Ignore .gitignore / .ignore and search everything fd -I node_modules # Lift both at once (unrestricted) fd -u secret
-u is shorthand for --no-ignore --hidden (equivalent to -HI).
To explicitly exclude a directory instead, use -E (--exclude):
# Exclude .git and build output fd -E .git -E dist -e js
How Do You Run a Command on Each Result?
Conclusion:
-x(--exec) runs a command per result in parallel;-X(--exec-batch) runs it once with all results. Both are faster and shorter thanfind -exec.
-x / -X replace find ... -exec, and placeholders embed each result.
# Delete each .tmp file (run in parallel) fd -e tmp -x rm # Pass all .png files to optipng at once (single process) fd -e png -X optipng
Placeholders (usable inside -x):
{}… full matched path{/}… file name only (basename){//}… parent directory{.}… path without extension{/.}… file name without extension
Example: convert every .jpg to a same-named .png:
fd -e jpg -x convert {} {.}.pngFor destructive operations like -x rm, first eyeball the list with fd -e tmp (no exec) before running it. Because fd respects .gitignore, unexpected files may be missing from — or included in — the results.
When Should You Use find vs fd?
Conclusion: Use fd for everyday searches and find for complex conditions, formatted output, or POSIX-only environments. They are not exclusive — make fd primary for speed and convenience, find secondary for special conditions.
Cases where fd is enough:
# Files changed within the last 10 minutes fd --changed-within 10min # Files larger than 1MB fd -S +1M # When you prefer glob syntax fd -g '*.config.js'
Cases to choose find:
- You need
-printffor finely formatted output - Compound time comparisons like
-newer fileA ! -newer fileB - Production servers where you cannot (or will not) install fd (it is not standard)
Copy-paste: common patterns
fd PATTERN # Recursive search by name fd -e log # Filter by extension fd -t d PATTERN # Directories only fd -H -I PATTERN # Search including hidden/ignored fd -e tmp -x rm # Run a command per result fd --changed-within 1d # Changed in the last day