fd is a fast, user-friendly alternative to find. You give it a pattern, and it
searches your filesystem for entries whose names match — using a regular expression by
default, or a glob if you ask for one. Out of the box it skips hidden files, honors your
.gitignore rules, searches case-insensitively until your pattern says otherwise, and
prints colorized results in parallel across all your CPU cores.
This guide covers everything you can do with fd from the command line: installing it,
running your first search, every option it accepts, and recipes for the tasks people reach
for fd to solve. Architecture, internals, and deep configuration live in the companion
Admin Guide.
Note
On Debian, Ubuntu, and their derivatives the binary is installed as
fdfindinstead offd, because the namefdis already taken by another package. Everywhere else in this guide, readfdasfdfindif you installed it that way. Many users add an alias:alias fd=fdfind.
1. Quick Start
Find every file or directory whose name contains netflix, starting in the current
directory:
fd netflix
projects/netflix-clone
projects/netflix-clone/README.md
notes/netflix-passwords.txt
The first argument is a regular expression, matched against the name of each entry (not the full path). The search is recursive, skips hidden and ignored files, and is case-insensitive as long as your pattern is all lowercase.
A few more starters:
fd '^README' # names that start with "README"
fd '\.jpg$' # names ending in .jpg (regex)
fd -e jpg # the same, but using the extension filter (preferred)
fd -e md -e txt notes # names containing "notes" with extension md or txt
fd # no pattern: list everything (that isn't hidden/ignored)
fd . src # match everything, but only under the src/ directory
Tip
When you want all files, use
fdwith no pattern, or use.as the pattern when you also need to give a search directory:fd . path/to/dir.
2. Installation
fd is a single self-contained binary written in Rust. There is nothing to configure
after installation and no runtime dependencies (one optional exception: --list-details
shells out to ls).
Prebuilt binary
Every release ships prebuilt binaries for Linux, macOS, and Windows on the project's
GitHub Releases page. Download the archive for your platform, extract it, and place the
fd executable somewhere on your PATH:
# Example: Linux x86_64
tar xzf fd-v10.4.2-x86_64-unknown-linux-gnu.tar.gz
sudo install fd-v10.4.2-x86_64-unknown-linux-gnu/fd /usr/local/bin/
Windows release archives are distributed as .zip files.
cargo (from crates.io)
If you have a Rust toolchain, install the fd-find crate. The crate is named
fd-find, but the installed binary is named fd:
cargo install fd-find
Installing fd-find v10.4.2
...
Installed package `fd-find v10.4.2` (executable `fd`)
cargo-binstall
To grab the prebuilt release binary without compiling, use
cargo-binstall:
cargo binstall fd-find
Build from source
git clone https://github.com/sharkdp/fd
cd fd
cargo build --release
# binary is at ./target/release/fd
Important
Building from source requires Rust 1.90.0 or newer (the project's minimum supported Rust version) and uses the 2024 edition. Use
rustup updateif your toolchain is older.
Note
fdis also packaged for many operating systems (Homebrew, the major Linux distributions, Scoop/Chocolatey on Windows, and more). Package names and the exact command vary by system; consult your package manager. Remember thefdfindrename on Debian/Ubuntu noted above.
Verifying the installation
fd --version
fd 10.4.2
Shell completions
fd can generate completion scripts for your shell on the fly:
fd --gen-completions bash > fd.bash
fd --gen-completions zsh > _fd
fd --gen-completions fish > fd.fish
If you omit the shell name, fd tries to detect it from your environment. Install the
generated file wherever your shell looks for completions.
Note
Completion generation is only available when
fdwas built with thecompletionsfeature, which is enabled in the default build and in all official release binaries.
3. How fd Searches: The Defaults You Should Know
Before the option reference, it pays to understand the five behaviors fd applies unless
you tell it otherwise. They are what make fd pleasant — and occasionally surprising.
| Default | What it means | How to turn it off |
|---|---|---|
| Smart case | All-lowercase pattern → case-insensitive. Any uppercase letter → case-sensitive. | -s (force sensitive) / -i (force insensitive) |
| Skip hidden | Entries whose name starts with . are not shown. |
-H / --hidden |
| Respect ignore files | .gitignore, .ignore, .fdignore, and the global ignore are honored. |
-I / --no-ignore |
| Match the name only | The pattern is matched against the file name, not the whole path. | -p / --full-path |
| Regex pattern | The pattern is a regular expression. | -g / --glob |
Tip
-u/--unrestrictedis the quick "show me everything" switch — it is an alias for--no-ignore --hidden. Pass it twice (-uu) to also disable.gitignorehandling entirely, just likerg -uu.
Important
"Smart case" looks at your pattern for any uppercase character.
fd readmematchesREADME.md, butfd Readmewill not, because the capitalRswitchesfdinto case-sensitive mode. This is the single most common source of "why didn't it match?" confusion (see issue #2013).
4. Everyday Usage
This section groups the options by the task you are trying to accomplish. Section 5 is the exhaustive flag reference if you prefer to look options up directly.
4.1 Choosing how the pattern is interpreted
fd 'foo.*bar' # regex (default): "foo", any chars, "bar"
fd -g '*.txt' # glob: shell-style wildcard
fd -F 'a.b.c' # fixed/literal substring — dots are literal, not regex
fd --exact main.rs # literal AND whole-name match (not a substring)
-g/--globswitches to glob syntax (*,?,[...],**). A*does not cross directory separators.-F/--fixed-strings(alias--literal) treats the pattern as a plain string; regex metacharacters lose their meaning. It still matches as a substring.--exactis like--fixed-stringsbut the pattern must match the entire name (or entire path with-p), not just part of it.
Require several patterns at once with --and (every pattern must match):
fd foo --and bar --and '\.txt$' # name contains foo AND bar AND ends in .txt
4.2 Controlling case
fd -s Config # case-sensitive: matches Config, not config
fd -i CONFIG # case-insensitive: matches config, Config, CONFIG
4.3 Including hidden and ignored files
fd -H secret # include hidden files (dotfiles, .config, ...)
fd -I target # include files normally hidden by .gitignore/.ignore
fd -u pattern # unrestricted: hidden + ignored (= -H -I)
fd -uu pattern # also ignore .gitignore rules completely
Finer-grained ignore control:
| Option | Effect |
|---|---|
--no-ignore-vcs |
Stop honoring .gitignore (but keep .ignore/.fdignore). |
--no-ignore-parent |
Stop reading ignore files in parent directories. |
--no-require-git |
Honor gitignore rules even when not inside a git repository. |
--ignore-file <path> |
Add your own ignore file (in .gitignore format). |
Note
By default
fdonly applies.gitignorerules when it detects you are inside a git repository. If you keep.gitignorefiles outside of git repos and want them respected, add--no-require-git.
4.4 Filtering by type, extension, size, time, and owner
By type with -t/--type (repeatable):
fd -t f config # only regular files
fd -t d src # only directories
fd -t l # only symlinks
fd -t x # only executable files
fd -t e # only empty files or directories
fd -t f -t l config # files OR symlinks
| Value | Aliases | Matches |
|---|---|---|
file |
f |
Regular files |
directory |
d, dir |
Directories |
symlink |
l |
Symbolic links |
executable |
x |
Files executable by you (implies file) |
empty |
e |
Empty files or directories |
socket |
s |
Sockets |
pipe |
p |
Named pipes (FIFOs) |
block-device |
b |
Block devices |
char-device |
c |
Character devices |
By extension with -e/--extension (repeatable). This is cleaner than a regex:
fd -e md # all Markdown files
fd -e jpg -e png -e gif # images
fd -e rs main # Rust files whose name contains "main"
By size with -S/--size, using <+|->NUM<UNIT>:
fd -S +10m # files at least 10 MB
fd -S -1k # files at most 1 KB
fd -S +1g -S -5g # between 1 GB and 5 GB (combine constraints)
+ means "at least", - means "at most", and no sign means "exactly". Units (case
insensitive): b bytes; k/m/g/t for decimal KB/MB/GB/TB (powers of 1000);
ki/mi/gi/ti for binary KiB/MiB/GiB/TiB (powers of 1024). A trailing b is allowed
(kb, mib).
By modification time with --changed-within and --changed-before:
fd --changed-within 2weeks # modified in the last two weeks
fd --changed-within 1d # modified in the last day
fd --changed-before 2020-01-01 # older than a fixed date
fd --changed-within '2018-10-27 10:00:00'
The argument is either a duration (10h, 1d, 35min, 2weeks) or a point in
time (YYYY-MM-DD, YYYY-MM-DD HH:MM:SS, or @<unix-timestamp>). Handy aliases:
--newer/--changed-after/--change-newer-than for --changed-within, and
--older/--change-older-than for --changed-before.
By owner (Unix only) with -o/--owner, format [user|uid][:group|gid]:
fd -o john # owned by user john
fd -o :developers # owned by group developers
fd -o john:developers # both
fd -o '!root' # NOT owned by root (prefix a side with !)
4.5 Limiting how deep and how wide
fd -d 2 pattern # search at most 2 directories deep
fd --min-depth 3 # only show results at least 3 levels down
fd --exact-depth 2 # only results at exactly depth 2
fd -E '*.pyc' -E node_modules pattern # exclude globs (repeatable)
fd --prune -t d cache # match dirs named cache but don't descend into them
fd --max-results 5 # stop after 5 results
fd -1 config # stop at the first result (alias for --max-results=1)
Tip
--exclude/-Eis faster and more predictable than adding things to an ignore file when you just want to skip a directory for one search, e.g.fd -E .git.
4.6 Choosing where to search
fd pattern # search the current directory
fd pattern ~/projects # search a specific directory
fd pattern dir1 dir2 dir3 # search several directories
fd --search-path ~/a --search-path ~/b pattern # same, via an option
fd -C ~/projects pattern # change working dir first, then search
The directory argument(s) come after the pattern. --search-path is an alternative
that is convenient in scripts. -C/--base-directory changes fd's working directory
before searching, so results are shown relative to that base.
4.7 Shaping the output
fd -a pattern # print absolute paths
fd -l pattern # long "ls -l" listing (size, permissions, dates)
fd -p '**/.git/config' # match against the full path, not just the name
fd -0 pattern # separate results with NUL (for xargs -0)
fd -c never pattern # disable colors (also: NO_COLOR env var)
fd --format '{}.bak' # apply an output template (see below)
fd --hyperlink # emit terminal hyperlinks to each result
The format template (--format) and the exec placeholders share the same syntax:
| Placeholder | Expands to |
|---|---|
{} |
The full path of the result |
{/} |
The basename (filename only) |
{//} |
The parent directory |
{.} |
The path with its extension removed |
{/.} |
The basename with its extension removed |
fd -e txt --format '{//} -> {/}'
notes -> todo.txt
notes -> ideas.txt
Note
-l/--list-detailsis essentially--exec-batch ls -lwith a fewlsoptions added. On Windows it requires GNUlsto be installed (see Troubleshooting).
4.8 Running a command on each result
This is fd's most powerful feature. Use -x/--exec to run a command per result (in
parallel), or -X/--exec-batch to run one command with all results as arguments.
# Run a command for each match (parallel):
fd -e zip -x unzip # unzip every .zip file
fd -e jpg -x convert {} {.}.png # convert each .jpg to .png next to it
fd -e h -e cpp -x clang-format -i # format each C/C++ file in place
# Run one command with all matches at once (batch):
fd -g 'test_*.py' -X vim # open all matching files in one editor
fd -e rs -X wc -l # count total lines across all .rs files
The same {}, {/}, {//}, {.}, {/.} placeholders apply. If you don't include a
placeholder, fd appends an implicit {} to the end of your command. Escape literal
braces with {{ and }}.
Tip
Put
-x/-Xlast on the command line. Everything after it is treated as part of the command, not asfdoptions. If you must continue with morefdflags afterward, terminate the command template with\;.
Caution
fd -xruns commands in parallel with no guaranteed order. If your command must run one at a time (or order matters), add-j 1/--threads 1. For-Xbatch mode, if there are more results than fit on one command line,fdautomatically splits them into multiple invocations; control the chunk size with--batch-size.
4.9 Performance and quiet checks
fd -j 4 pattern # use 4 threads (default: all available cores)
fd -q pattern # print nothing; exit 0 if anything matched, else 1
fd --show-errors # surface permission/dead-symlink errors (normally hidden)
-q/--quiet (alias --has-results) is built for scripts:
if fd -q -e lock; then echo "lock files present"; fi
5. Complete Option Reference
fd's usage is fd [OPTIONS] [pattern] [path...]. The table below lists every option.
Options marked (hidden) are accepted but not shown in fd --help; most have a visible
counterpart they override.
Search behavior
| Option | Description |
|---|---|
-H, --hidden |
Include hidden files and directories. |
-I, --no-ignore |
Don't respect .gitignore/.ignore/.fdignore/global ignore. |
--no-ignore-vcs |
Don't respect .gitignore files. |
--no-require-git |
Respect gitignore rules even outside a git repository. |
--no-ignore-parent |
Don't respect ignore files in parent directories. |
--no-global-ignore-file (hidden) |
Don't respect the global ignore file. |
-u, --unrestricted |
Alias for --no-ignore --hidden; repeat (-uu) to also drop .gitignore. |
-s, --case-sensitive |
Case-sensitive search. |
-i, --ignore-case |
Case-insensitive search. |
-g, --glob |
Glob-based search instead of regex. |
--regex |
Regex-based search (the default; use to override --glob). |
-F, --fixed-strings (--literal) |
Treat the pattern as a literal substring. |
--exact |
Match the entire filename exactly (literal, non-substring). |
--and <pattern> |
Additional required pattern; may be given multiple times. |
-p, --full-path |
Match the pattern against the full path, not just the name. |
Filters
| Option | Description |
|---|---|
-t, --type <filetype> |
Filter by type (f, d, l, x, e, s, p, b, c). Repeatable. |
-e, --extension <ext> |
Filter by file extension. Repeatable. |
-S, --size <size> |
Filter by size, e.g. +10m, -1k, 100ki. Repeatable. |
--changed-within <date|dur> |
Modified more recently than the given time/duration. |
--changed-before <date|dur> |
Modified before the given time/duration. |
-o, --owner <user:group> |
(Unix) Filter by owning user/group; ! negates. |
-E, --exclude <glob> |
Exclude entries matching a glob. Repeatable. |
--ignore-file <path> |
Add a custom ignore file in .gitignore format. |
--ignore-contain <name> |
Skip directories that contain an entry with this name. |
--prune |
Don't descend into matching directories. |
Depth and result limits
| Option | Description |
|---|---|
-d, --max-depth <depth> (--maxdepth) |
Limit traversal depth. |
--min-depth <depth> (--mindepth) |
Only show results at or below this depth. |
--exact-depth <depth> |
Only show results at exactly this depth. |
--max-results <count> |
Stop after this many results. |
-1 |
Stop at the first result (alias for --max-results=1). |
-q, --quiet (--has-results) |
Print nothing; exit 0 on any match, 1 otherwise. |
Traversal control
| Option | Description |
|---|---|
-L, --follow (--dereference) |
Follow symbolic links. |
--one-file-system (--mount, --xdev) |
Don't cross filesystem boundaries. |
-j, --threads <num> |
Number of threads for searching/executing. |
-C, --base-directory <path> |
Change working directory before searching. |
[path...] |
Root directories to search (default: current directory). |
--search-path <path> |
Search root as an option instead of a positional argument. Repeatable. |
Output
| Option | Description |
|---|---|
-a, --absolute-path |
Print absolute instead of relative paths. |
-l, --list-details |
Long listing format (like ls -l). |
-0, --print0 |
Separate results with the NUL character. |
--format <fmt> |
Print results using a template ({}, {/}, {//}, {.}, {/.}). |
-c, --color <when> |
Colorize: auto (default), always, never. |
--hyperlink[=<when>] |
Emit terminal hyperlinks: auto, always, never (default). |
--path-separator <sep> |
Override the path separator in printed paths. |
--strip-cwd-prefix[=<when>] |
Control stripping of the leading ./: auto, always, never. |
Command execution
| Option | Description |
|---|---|
-x, --exec <cmd>... |
Run a command for each result, in parallel. |
-X, --exec-batch <cmd>... |
Run one command with all results as arguments. |
--batch-size <size> |
Max arguments per -X invocation (0 = unlimited). |
Other
| Option | Description |
|---|---|
--show-errors |
Show filesystem errors (permissions, dead symlinks). |
--gen-completions [shell] (hidden) |
Generate a shell completion script. |
-h, --help |
Print help (--help shows the long help). |
-V, --version |
Print version information. |
Note
Several "negative" flags exist purely to override an earlier flag on the command line —
--no-hidden,--ignore,--ignore-vcs,--require-git,--ignore-parent,--relative-path,--no-follow. They are hidden from help because you rarely type them directly;fduses "last one wins" semantics so a later flag overrides an earlier one.
6. Recipes
Practical one-liners for common jobs.
Find and delete all .DS_Store files:
fd -H -t f '\.DS_Store$' -X rm
Find large log files and compress them:
fd -e log -S +100m -x gzip
Rename .jpeg files to .jpg:
fd -e jpeg -x mv {} {.}.jpg
List the 10 most recently modified source files:
fd -e rs --changed-within 7d
Pipe results into another tool safely (handles spaces/newlines in names):
fd -0 -e txt | xargs -0 wc -l
Search only the top level (no recursion):
fd -d 1
Find empty directories and remove them:
fd -t e -t d -X rmdir
Count files by running a batch command:
fd -t f -X echo | wc -w
Open all matching files in your editor at once:
fd -g '*.conf' /etc -X $EDITOR
Warning
Recipes that delete or overwrite (
rm,mv,gzip) act on whateverfdmatches. Run the search without-x/-Xfirst to review the list, then add the command.
7. Ignoring Files Permanently
Beyond .gitignore, fd reads two ignore files of its own:
.fdignore— placed anywhere in your project, same syntax as.gitignore. Applies tofdonly.- Global ignore file — patterns that apply to every
fdsearch on your machine.
The global ignore file lives in fd's config directory: on Linux/macOS that is
~/.config/fd/ignore (or $XDG_CONFIG_HOME/fd/ignore). Create it and add one glob per
line:
# ~/.config/fd/ignore
.git/
node_modules/
*.tmp
Tip
Use
.fdignorefor project-specific noise you don't want to add to.gitignore, and the global ignore file for things you never want to see anywhere (build caches, editor temp files).
8. Exit Codes
fd returns a standard exit code so you can use it in scripts and pipelines.
| Code | Meaning |
|---|---|
0 |
Success. (With -q/--quiet: at least one match was found.) |
1 |
A general error occurred. (With -q/--quiet: no match was found.) |
130 |
Interrupted by Ctrl+C (SIGINT). |
Note
When you use
-x/-X,fd's exit code reflects the commands it ran: if any executed command exits non-zero,fdexits1.
9. Troubleshooting
Each entry shows the exact message fd prints (all errors are prefixed with
[fd error]:), why it happens, and how to fix it.
Error: The search pattern '...' contains a path-separation character and will not lead to any search results.
Cause: Your pattern contains a / (or, on Windows, a \ that names a real directory).
By default fd matches only the file name, so a pattern with a path separator can never
match.
Solution: To list everything inside a directory, use a match-all pattern and pass the
directory as the search path: fd . some/dir. To match against the full path instead, add
-p/--full-path: fd -p some/dir.
Prevention: Remember that the default search target is the name only; reach for -p
when you mean the whole path.
Error: The pattern(s) seems to only match files with a leading dot, but hidden files are filtered by default...
Cause: Your pattern (e.g. ^\.gitignore) only matches hidden files, but hidden files
are skipped by default, so the search would always return nothing.
Solution: Add -H/--hidden to include hidden files, or adjust the pattern.
Why does fd search case-insensitively / case-sensitively unexpectedly?
Cause: Smart case. An all-lowercase pattern is case-insensitive; any uppercase character makes the whole search case-sensitive (issue #2013).
Solution: Force the behavior explicitly with -i (insensitive) or -s (sensitive).
Error: '...' is not a valid size constraint. See 'fd --help'.
Cause: A malformed -S/--size value. The format is <+|->NUM<UNIT>, e.g. +10m.
Solution: Use a sign (+/-/none), a number, and a valid unit (b, k, m, g,
t, ki, mi, gi, ti). Examples: -S +1g, -S -500k, -S 1mi.
Error: '...' is not a valid date or duration. See 'fd --help'.
Cause: A --changed-within/--changed-before value that isn't a recognized duration
or timestamp.
Solution: Use a duration like 2weeks, 1d, 35min, or a date like 2020-01-01,
'2020-01-01 12:00:00', or @1577836800 (Unix timestamp with a leading @).
Error: '...' is not a recognized user name / '...' is not a recognized group name
Cause: The -o/--owner value names a user or group that doesn't exist on the system.
Solution: Use a valid name, or a numeric uid/gid. Format: user:group, either side
optional, ! to negate.
Error: 'fd --list-details' is not supported on Windows unless GNU 'ls' is installed.
Cause: -l/--list-details shells out to ls, which isn't present on a stock Windows
system (issue #1482, common with nushell).
Solution: Install GNU ls (e.g. via Git for Windows / MSYS2 / coreutils) and ensure
it's on your PATH, or avoid -l on Windows and use --format instead.
Error: A path separator must be exactly one byte, but the given separator is N bytes: '...'.
Cause: On Windows, some shells expand / in arguments, so --path-separator / arrives
as something longer.
Solution: Use // instead, as the message suggests.
Error: Command not found: ... (e.g. with -x cd)
Cause: -x/-X execute real programs, not shell built-ins. cd, export, and
similar are shell built-ins, not executables (issue #1944).
Solution: Wrap the built-in in a shell: fd -x bash -c 'cd {} && ...'.
Error: No executable provided for --exec or --exec-batch
Cause: -x/-X was given without a command to run.
Solution: Provide the command, e.g. fd -e txt -x cat.
Error: Only one placeholder allowed for batch commands / First argument of exec-batch is expected to be a fixed executable
Cause: With -X/--exec-batch, the command may contain at most one placeholder, and
the program name (first argument) must be fixed, not a placeholder.
Solution: Restructure the batch command so the executable is literal and only one
placeholder appears, e.g. fd -e rs -X wc -l.
Error: Search path '...' is not a directory. / No valid search paths given.
Cause: A path argument doesn't point to an existing directory.
Solution: Check the path. fd warns about each bad path and exits with "No valid
search paths given" if none remain.
fd doesn't seem to exit when its output pipe is closed
Cause: A known edge case with full-path search and globbing when the downstream of a pipe closes (issue #1479).
Solution: Track the upstream issue; for most pipelines fd exits cleanly on a broken
pipe.
10. Frequently Asked Questions
Q: Is fd a drop-in replacement for find?
A: No — it's an alternative with friendlier defaults and syntax, not a find clone. It
covers the most common find use cases with far less typing, but doesn't replicate every
find expression.
Q: How do I search for all files, including hidden and ignored ones?
A: fd -u (or fd -uu to also ignore .gitignore rules). -u is short for
--no-ignore --hidden.
Q: Why didn't my uppercase pattern match a lowercase file?
A: Smart case made the search case-sensitive because the pattern has an uppercase letter.
Use -i to force case-insensitive matching.
Q: How do I match against the whole path instead of just the filename?
A: Use -p/--full-path, e.g. fd -p '**/.git/config'.
Q: What's the difference between --glob and the default?
A: The default is a regular expression. --glob switches to shell-style wildcards
(*, ?, [...]).
Q: How do I exclude a directory like node_modules?
A: fd -E node_modules, or add it to a .fdignore/global ignore file.
Q: How do I run a command on every result?
A: fd <pattern> -x <command> (per result, parallel) or -X (all results at once).
Place -x/-X last.
Q: How do I make -x run commands one at a time?
A: Add -j 1 to use a single thread.
Q: How do I get NUL-separated output for xargs?
A: fd -0 ... | xargs -0 ....
Q: Why are colors disabled when I pipe fd into another command?
A: Color defaults to auto, which only colorizes an interactive terminal. Force it with
-c always. You can also disable color globally with the NO_COLOR environment variable.
Q: How do I limit search depth?
A: -d N/--max-depth N. Combine with --min-depth/--exact-depth for a depth window.
Q: How do I filter by size or modification time?
A: -S +10m (size) and --changed-within 2weeks / --changed-before 2020-01-01 (time).
Q: Does fd follow symlinks?
A: Not by default. Add -L/--follow.
Q: Where do I report bugs? A: On GitHub at https://github.com/sharkdp/fd/issues.
Q: The binary is called fdfind on my system — why?
A: On Debian/Ubuntu the name fd was already taken, so the package installs the binary as
fdfind. Add alias fd=fdfind to your shell config.