fd: A Simpler, Faster Alternative to find

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 fdfind gotcha (the command isn't called fd)
  • Master the real-world patterns: extensions, types, gitignore handling, -x exec

Quick Summary

  • Everyday "where is that file?"fd PATTERN (fast, short, colorized)
  • Search even ignored filesfd -H -I PATTERN
  • When you still need find → complex -newer conditions, -printf formatting, 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 named fdfind, not fd. The common fix is a symlink or alias to expose it as fd.

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 PATTERN searches 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 EXT and 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 file
  • d … directory
  • l … symlink
  • x … executable
  • e … 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 -H to include hidden files, -I to 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 than find -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 {} {.}.png

For 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 -printf for 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

Next Reading