- cli
- l1
- topic-pack
- fd --- Portal | Level: L1: Foundations | Topics: fd | Domain: CLI Tools
fd — Fast Find Alternative Primer¶
Why This Matters¶
find is powerful but its syntax is archaic and it is slow on large directory trees. fd is a modern replacement: faster (parallel traversal), friendlier syntax, respects .gitignore by default, and produces colorized output. For DevOps work — locating configs, cleaning temp files, executing batch operations — fd eliminates the friction of find.
Name origin: fd is written in Rust by David Peter (sharkdp), first released in 2017. The name is short for "find" — a deliberate abbreviation. The same author also created bat (cat replacement) and hyperfine (benchmarking tool).
Under the hood: fd is typically 5-10x faster than find on large directory trees because it uses parallel directory traversal and avoids searching inside .git/ and other ignored directories. On a repo with 100,000 files, the difference is seconds vs. milliseconds.
Core Concepts¶
Basic Search¶
# Find files matching a pattern (substring match, case-insensitive by default)
fd nginx
# Find in a specific directory
fd config /etc/
# Find with full path matching
fd --full-path '/etc/.*\.conf$'
fd searches recursively from the current directory by default. Unlike find, you do not need . or -name.
Regex vs Glob¶
# Default: regex pattern
fd '^test.*\.py$'
# Glob mode
fd -g '*.yaml'
# Fixed string (no regex interpretation)
fd -F 'config.yaml'
Type Filters¶
# Files only
fd -t f "log"
# Directories only
fd -t d "config"
# Symlinks only
fd -t l
# Executable files only
fd -t x
| Short | Long | Matches |
|---|---|---|
-t f |
--type file |
Regular files |
-t d |
--type directory |
Directories |
-t l |
--type symlink |
Symbolic links |
-t x |
--type executable |
Executable files |
-t e |
--type empty |
Empty files/dirs |
Extension Filter¶
# Find by extension (faster than regex for simple cases)
fd -e yaml
fd -e py
fd -e tf
# Combine extensions
fd -e yaml -e yml
Hidden Files and Ignore Rules¶
By default, fd skips hidden files (dotfiles) and respects .gitignore:
# Include hidden files
fd --hidden "bashrc"
# Include .gitignore'd files
fd --no-ignore "node_modules"
# Include both hidden and ignored
fd --hidden --no-ignore "secret"
# Only search files tracked by git
fd --no-ignore-vcs
Depth and Excludes¶
# Maximum depth
fd -d 2 "README"
# Exclude directories or patterns
fd -E node_modules -E .git -E '*.bak' "config"
Executing Commands¶
fd can run commands on each match, replacing find -exec:
# Run a command on each result
fd -e py --exec python3 -m py_compile {}
# Batch execution (single process, all matches as args)
fd -e sh --exec-batch shellcheck {}
Placeholder tokens: {} (full path), {/} (basename), {//} (parent dir), {.} (no extension), {/.} (basename, no extension).
Remember: fd placeholder mnemonic:
{}= full path (curly = complete),{/}= basename (slash strips the path),{.}= no extension (dot removes the dot-extension). The slashes and dots in the placeholders hint at what they strip.
exec vs exec-batch¶
--exec runs the command once per match (parallel). --exec-batch runs it once with all matches as arguments (like xargs).
Size and Time Filters¶
# Files larger than 10MB
fd -t f --size +10m
# Modified in the last 24 hours
fd -t f --changed-within 24h
# Modified more than 7 days ago
fd -t f --changed-before 7d
Practical DevOps Patterns¶
# Find all Dockerfiles
fd -g 'Dockerfile*'
# Clean up old temp files
fd -e tmp -e bak --changed-before 30d --exec rm {}
# Verify all shell scripts pass syntax check
fd -e sh --exec-batch bash -n
# Find large log files consuming disk
fd -e log -t f --size +100m --exec ls -lh {}
# Null-separated output (safe for xargs)
fd -0 -e py | xargs -0 ruff check
Gotcha: fd is case-insensitive by default (unlike find). If you search
fd README, it also matchesreadmeandReadme. Use-s(or--case-sensitive) when you need exact case matching. This is the opposite default fromfind -name, which is case-sensitive.
fd vs find¶
| Task | find | fd |
|---|---|---|
| Find by name | find . -name '*.yaml' |
fd -e yaml |
| Type filter | find . -type f |
fd -t f |
| Execute | find . -exec cmd {} \; |
fd --exec cmd {} |
| Exclude dir | find . -not -path '*/node_modules/*' |
fd -E node_modules |
| Speed | Single-threaded | Multi-threaded |
| .gitignore | Not aware | Respected by default |
Configuration¶
Create a ~/.fdignore or project .fdignore (same syntax as .gitignore):
fd also reads .ignore files (shared with rg).
One-liner:
fd -e yaml -e yml --exec-batch yamllint— find all YAML files and lint them in a single invocation. The--exec-batchflag passes all matches as arguments to one process, likexargsbut without the pipe.Interview tip: "How would you find all log files over 100MB modified in the last week?" Answer:
fd -e log -t f --size +100m --changed-within 7d. This demonstrates modern CLI fluency. The find equivalent isfind . -name '*.log' -type f -size +100M -mtime -7— functional but less readable.
Wiki Navigation¶
Related Content¶
- Modern CLI Tools (Topic Pack, L0) — fd
- Skillcheck: Modern CLI Tools (Assessment, L0) — fd
- fd Flashcards (CLI) (flashcard_deck, L1) — fd