Jesse A. Green / notebook

fd User Guide

Generated June 2026 from sharkdp/fd at f7d4d71

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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 fdfind instead of fd, because the name fd is already taken by another package. Everywhere else in this guide, read fd as fdfind if 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 fd with 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 update if your toolchain is older.

Note

fd is 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 the fdfind rename 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 fd was built with the completions feature, 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/--unrestricted is the quick "show me everything" switch — it is an alias for --no-ignore --hidden. Pass it twice (-uu) to also disable .gitignore handling entirely, just like rg -uu.

Important

"Smart case" looks at your pattern for any uppercase character. fd readme matches README.md, but fd Readme will not, because the capital R switches fd into 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/--glob switches 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.
  • --exact is like --fixed-strings but 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 fd only applies .gitignore rules when it detects you are inside a git repository. If you keep .gitignore files 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/-E is 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.

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-details is essentially --exec-batch ls -l with a few ls options added. On Windows it requires GNU ls to 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/-X last on the command line. Everything after it is treated as part of the command, not as fd options. If you must continue with more fd flags afterward, terminate the command template with \;.

Caution

fd -x runs 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 -X batch mode, if there are more results than fit on one command line, fd automatically 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; fd uses "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 whatever fd matches. Run the search without -x/-X first 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 to fd only.
  • Global ignore file — patterns that apply to every fd search 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 .fdignore for 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, fd exits 1.


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.