You keep a line like find . -name '*.py' -not -path './node_modules/*' in a notes file because you never remember its order, and you still get node_modules noise when you forget the -not -path part. fd is a small program that finds files by name with a shorter command, skips what your .gitignore already ignores, and runs a command on every result.
This guide covers the 20% of fd that does 80% of the work: matching names with plain text, regular expressions, and globs; filtering by extension, type, depth, and size; ignore rules and hidden files; and running commands with -x and -X. A searchable command reference and a set of videos, books, and online resources close the article.
What You’ll Learn
- What fd does, and when
findstill fits better. - How to find files by name with plain text, regular expressions, and globs.
- How to narrow results by extension, file type, depth, and size.
- Why fd skips some files, and how to see them with
-H,-I, and-u. - How to run a command on every result with
-xand-X. - Where to go next to learn more about fd.
When to Use fd or find
fd searches the current folder and every folder below it for names that match a pattern. It prints paths relative to where you run it, skips hidden files and anything your ignore files list, and treats the pattern as a regular expression unless you ask for a glob. Those defaults fit the search you run most days: find a file in a project by part of its name.
Each find command below has a shorter fd equivalent:
find . -name '*cart*'isfd cart.find . -name '*.py'isfd -e py.find . -type disfd -t d.find . -maxdepth 1 -type fisfd -t f -d 1.find . -name '*.py' -not -path './node_modules/*'isfd -e py, when a.gitignorelistsnode_modules/.find . -name '*.jpeg' -exec mv {} ... \;isfd -e jpeg -x mv {} {.}.jpg.
Keep find for the jobs fd leaves out:
- Matching by modification time relative to another file (
-newer) or by exact permission bits (-perm). - Scripts that must run on any POSIX system, where fd may not be installed.
- Complex conditions that combine
-o,!, and grouping in one expression. - Running a different action per match with several
-execclauses.
fd works the same in any shell. The examples below run in zsh, from a home folder that holds a few practice files: notes.txt, a logs/ folder, a photos/ folder, and a small web project in shop/ that is a git repository with a .gitignore.
Find Files by Name
Give fd part of a name. It matches anywhere in the file or folder name, below the current folder:
fd cart shopshop/src/cart.py
shop/src/test_cart.pyThe second argument is the folder to search. Leave it out and fd searches the current folder. fd matches only the last part of each path, the file or folder name, so the folders above a file never cause a match.
fd uses smart case. A pattern in lowercase ignores case, and a pattern with any uppercase letter matches case exactly. fd App shop prints nothing, because no name contains App with a capital A. Add -i to ignore case anyway, or -s to match case even for a lowercase pattern:
fd -i readme shopshop/README.mdUse Regex and Glob Patterns
The pattern is a regular expression. ^ anchors the start of the name and $ the end, so ^test_ finds files whose names start with test_:
fd '^test_' shopshop/src/test_cart.pyQuote patterns with special characters, so the shell passes them to fd unchanged. Escape a literal dot with a backslash, or use -F to treat the whole pattern as fixed text:
fd 'cart\.py$' shopshop/src/cart.py
shop/src/test_cart.pyUse -g when a shell-style glob reads better than a regular expression. A glob must match the whole name:
fd -g '*.py' shopshop/src/__init__.py
shop/src/app.py
shop/src/cart.py
shop/src/test_cart.pyTo match against the full path instead of the name, add -p. Then fd -p 'src/t' shop matches the templates folder and test_cart.py, because both paths contain src/t.
Filter by Extension, Type, Depth, and Size
-e filters by file extension, without the dot. It ignores case, so -e jpg also finds .JPG files:
fd -e jpgphotos/IMG_2043.JPGTo list every file with an extension, use . as the pattern. It matches any name:
fd -e py . shopshop/src/__init__.py
shop/src/app.py
shop/src/cart.py
shop/src/test_cart.pyRepeat -e to match several extensions, as in fd -e html -e css.
-t filters by type: f for files, d for directories, x for executables, and e for empty files and folders. Combine it with -d to limit how deep fd goes. -d 1 stays in the folder you search:
fd -t d -d 1logs/
photos/
shop/fd marks directories with a trailing /. Two more filters round out the set. -E excludes names that match a glob, and -S filters by size, such as -S +1M for files over one megabyte:
fd -e py -E 'test_*' . shopshop/src/__init__.py
shop/src/app.py
shop/src/cart.pyRespect .gitignore and Hidden Files
By default fd skips two kinds of entries: hidden files and folders, whose names start with a dot, and anything an ignore file lists. Inside shop/, .gitignore lists node_modules/, dist/, and *.log, so a plain fd in that folder shows only the project’s own files:
cd shop
fdREADME.md
run.sh
src/
src/__init__.py
src/app.py
src/cart.py
src/templates/
src/templates/index.html
src/test_cart.py
static/
static/style.cssAdd -H to include hidden entries such as .env and .gitignore, -I to include ignored ones, or -u for both. Run from the home folder, fd -e log lists the three files in logs/, and -I adds shop/debug.log, which shop/.gitignore hides:
fd -I -e loglogs/app-2026-09.log
logs/app.log
logs/error.log
shop/debug.logIn shop/, the same flag brings back node_modules/ and dist/. fd reads .gitignore only inside a git repository, a folder with a .git directory at or above it.
A .gitignore copied into a folder that isn’t a repository does nothing until you add --no-require-git:
mkdir ~/scratch
cp ~/shop/.gitignore ~/scratch/
echo hi > ~/scratch/debug.log
cd ~/scratch
fddebug.logRun fd --no-require-git in the same folder and it prints nothing, because the copied .gitignore now applies.
To hide files from fd without changing what git tracks, list them in .fdignore (fd only) or .ignore (fd, ripgrep, and other tools that read it). Each uses the same syntax as .gitignore:
cd shop
echo 'static/' > .fdignore
fdREADME.md
run.sh
src/
src/__init__.py
src/app.py
src/cart.py
src/templates/
src/templates/index.html
src/test_cart.pystatic/ and its stylesheet are gone. fd --no-ignore shows everything again. For patterns you never want to see in any folder, write them to ~/.config/fd/ignore. --no-global-ignore-file turns that file off for one search, and --no-ignore-vcs turns off only .gitignore.
Run Commands on Results with -x and -X
-x runs a command once for each result, and -X runs it once with every result as arguments. Placeholders in braces stand for parts of each path:
{}is the whole path,src/app.py.{.}is the path without its extension,src/app.{/}is the file name,app.py.{//}is the parent folder,src.{/.}is the file name without its extension,app.
When you leave out the placeholder, fd adds {} at the end. Rename every .jpeg file to .jpg. The mv prints nothing, so check the result with a second search. Sort it, because a renamed file moves to the end of its folder, and fd lists a slow search in the order it finds files:
fd -e jpeg -x mv {} {.}.jpg
fd -e jpg | sortphotos/IMG_2041.jpg
photos/IMG_2042.jpg
photos/IMG_2043.JPG-X suits commands that take many files at once, such as wc -l to count lines:
cd shop
fd -e py -X wc -l | sort 0 ./src/__init__.py
7 ./src/test_cart.py
11 ./src/app.py
13 ./src/cart.py
31 totalPaths that fd passes to a command start with ./, so a name that begins with - can’t pass for an option. And the output ends in | sort because the order varies. fd sorts its own results only when the search finishes within about 100 milliseconds, and otherwise prints them in the order it finds them. -x runs several commands at once and prints their output as each finishes, so its order changes from run to run. Pipe to sort whenever the order matters. -j 1 runs one command at a time.
Find every file that mentions TODO:
cd shop
fd -t f -X grep -l TODO | sort./README.md
./src/cart.pyFormat Output
A few flags change how fd prints each path:
-aprints absolute paths, starting at/.-lprints a long listing, likels -l, with permissions, owner, size, and date.-0ends each path with a NUL character instead of a newline, forxargs -0and other tools that read NUL-separated names safely.--color neverturns colors off;--color alwayskeeps them when you pipe toless -R.
fd -a -e css/home/reader/shop/static/style.cssPair -0 with xargs -0 when names may contain spaces:
cd shop
fd -0 -e py | xargs -0 wc -l 0 ./src/__init__.py
11 ./src/app.py
13 ./src/cart.py
7 ./src/test_cart.py
31 totalPractice fd
fd sticks once you type it. The practice shell below runs real fd 10.5.0 in zsh, in this page. Nothing downloads until you press Start, nothing you type leaves your browser, and Reset brings back a fresh shell. Click the shell to type.
The practice shell has no network and holds only fd, zsh, and BusyBox’s basic programs. Its home holds the practice files the examples above use: notes.txt, logs/, photos/, and the shop/ project with its .gitignore. These commands cannot run there, so run them on your own machine:
git,rg,fzf,zoxide,bat,curl,brew, andsudoare not installed, so zsh answerscommand not found.fd -x convertandfd -x ffmpegfail once per match, because neither program is installed.wget,ping,nc, andnslookupfail, because the practice shell has no network.
Practice the commands on this page in real fd, right here. Nothing downloads until Start (about 7 MB).
reader@practice ~ % fd cart shop shop/src/cart.py shop/src/test_cart.py reader@practice ~ %
The practice shell needs JavaScript. Every command in the reference also works in fd on your own machine.
Run the drill below in the practice shell or in your own terminal with the same files. Type each command exactly as shown and press Enter. It takes about ten minutes:
- Move into the project:
cd shop. The prompt changes toreader@practice ~/shop %. - List the Python files:
fd -e py. You seesrc/__init__.py,src/app.py,src/cart.py, andsrc/test_cart.py. Nothing fromnode_modulesordistshows up, because the project’s.gitignorelists them. - Add hidden files:
fd -H. The list now starts with.env,.git/,.git/HEAD, and.gitignore, then the 11 files and folders that plainfdshows.node_modules,dist, anddebug.logstay hidden, because-Hshows hidden files but still respects.gitignore. - Go back home with
cd, then list the log files:fd -e log. You seelogs/app-2026-09.log,logs/app.log, andlogs/error.log. Runfd -I -e logto stop respecting ignore files, andshop/debug.logjoins the list. - Rename the
.jpegphotos:fd -e jpeg -x mv {} {.}.jpg.{}is each match and{.}is the match without its extension. It prints nothing. Check the result withfd -e jpg | sort. You seephotos/IMG_2041.jpg,photos/IMG_2042.jpg, andphotos/IMG_2043.JPG, because-eignores the case of the extension. A renamed file moves to the end of its folder, and fd lists a slow search in the order it finds files, sosortkeeps the order fixed. - Press Reset shell. The renamed photos are back to
.jpeg, and the shell starts again in your home. Runfd -e jpegto see both.jpegphotos again. - Type
cd shand press Tab. zsh completes the line tocd shop/. Press Enter to move into the project.
To practice on your own machine, install fd first. On macOS, install fd with Homebrew:
Runs on your machine, not in the practice shell
brew install fdOn Debian and Ubuntu, the package is fd-find and the program is named fdfind, because another package already uses fd. Install it, then link fd to it in a folder on your PATH:
Runs on your machine, not in the practice shell
sudo apt install fd-find
mkdir -p ~/.local/bin
ln -s "$(command -v fdfind)" ~/.local/bin/fdWith a Rust toolchain on any platform, build it with cargo:
Runs on your machine, not in the practice shell
cargo install fd-findThen work through these steps in one of your own project folders that is a git repository:
- List every file fd sees:
fd -t f. Compare the count withfd -t f -u, which adds hidden and ignored files. The difference is what your ignore files hide. - Find a file by part of its name, such as
fd config. Then try the same word with a capital letter,fd Config, and see smart case match case exactly. - List one kind of file:
fd -e md, or any extension your project uses. Add-d 2to stay near the top. - List only folders, two levels deep:
fd -t d -d 2. - Find the files that mention
TODO:fd -t f -X grep -l TODO. - Count lines in every file of one kind:
fd -e md -X wc -l. Pipe it tosort -nto see the longest file last. - Hide a folder from fd without touching git: write its name to
.fdignore, runfdagain, then delete.fdignore.
Command Reference
Verified with fd 10.5.0. Search the reference to find a command fast. Each entry shows the command, then what it does.
Patterns
fd cart- Find names that containcart, ignoring case for a lowercase pattern (smart case)fd App- Match case exactly, because the pattern has an uppercase letterfd -s app- Match case exactly for any patternfd -i readme- Ignore case for any patternfd '^test_'- Find names that start withtest_(regular expression)fd 'cart\.py$'- Find names that end withcart.pyfd -F '.py'- Treat the pattern as fixed text, not a regular expressionfd -g '*.py'- Match a whole name with a glob instead of a regular expressionfd -p 'src/t'- Match the pattern against the full path, not only the namefd . src- List everything in one folder (.matches any name)
Filters
fd -e py- Find files with an extension, ignoring casefd -e html -e css- Find files with any of several extensionsfd -t f- Find files onlyfd -t d- Find directories onlyfd -t x- Find executable filesfd -t e- Find empty files and directoriesfd -d 1- Search one level deep at mostfd --min-depth 2- Skip results less than two levels deepfd -E 'test_*'- Exclude names that match a globfd -S +1M- Find files larger than one megabytefd -S -1k- Find files smaller than one kilobyte
Hidden and Ignored Files
fd -H- Include hidden files and foldersfd -I- Include files that an ignore file listsfd -u- Include hidden and ignored filesfd --no-ignore-vcs- Stop reading.gitignore, but keep.ignoreand.fdignorefd --no-require-git- Read.gitignoreoutside a git repositoryfd --no-global-ignore-file- Skip~/.config/fd/ignorefor one searchecho 'static/' > .fdignore- Hide a folder from fd onlyecho 'static/' > .ignore- Hide a folder from fd and other tools that read.ignoreecho '*.html' > ~/.config/fd/ignore- Hide a pattern from fd in every folder
Output
fd -a- Print absolute pathsfd -l- Print a long listing with permissions, size, and datefd -0- End each path with a NUL character, forxargs -0fd --color never- Turn colors off
Run Commands
fd -e jpeg -x mv {} {.}.jpg- Run a command once per resultfd -e py -X wc -l- Run a command once with every result as argumentsfd -x echo {}- Use the whole pathfd -x echo {.}- Use the path without its extensionfd -x echo {/}- Use the file namefd -x echo {//}- Use the parent folderfd -x echo {/.}- Use the file name without its extensionfd -j 1 -x wc -l- Run one command at a time
Examples
Each example runs on the practice files and shows what fd prints.
fd -e loglogs/app-2026-09.log
logs/app.log
logs/error.logfd -H . shop -d 1shop/.env
shop/.git/
shop/.gitignore
shop/README.md
shop/run.sh
shop/src/
shop/static/fd -t x . shopshop/run.shfd -t e . shopshop/src/__init__.pyfd -e py -x echo {/.} | sort__init__
app
cart
test_cartfd app shopshop/src/app.pyfd -F '.py' shopshop/src/__init__.py
shop/src/app.py
shop/src/cart.py
shop/src/test_cart.pyfd -p 'src/t' shopshop/src/templates/
shop/src/templates/index.html
shop/src/test_cart.pyfd -e html -e css . shopshop/src/templates/index.html
shop/static/style.cssfd -t d . shopshop/src/
shop/src/templates/
shop/static/fd -I -t d -d 2 . shopshop/dist/
shop/node_modules/
shop/node_modules/left-pad/
shop/src/
shop/src/templates/
shop/static/fd --min-depth 3 -e pyshop/src/__init__.py
shop/src/app.py
shop/src/cart.py
shop/src/test_cart.pyfd -e py -x echo {//} | sort -u./shop/srcLearn fd: Beyond the Basics
With names, filters, ignore rules, and -x in hand, these resources take you further. Start with a video, then keep fd’s manual open while you replace the find lines in your notes.
Video
- The Modern UNIX command “fd” replaces the “find” command with a twist by Akamai Developers, a walkthrough of fd’s defaults next to
find. - The FAST Way to Find Files from the Command Line by Eric Murphy, a short tour of everyday fd searches.
- How to Use fd: Fast File Searching in Linux by LinuxHowTo, installation and the common flags on Linux.
Books
- Efficient Linux at the Command Line by Daniel J. Barrett, on combining small commands such as
find,xargs, andsortinto fast workflows. - The Linux Command Line by William Shotts, free online, with chapters on searching for files and on
xargs.
Online
- fd on GitHub, the README with installation for every platform, a feature tour, and benchmarks.
- fd’s manual page, the full list of options and placeholders.
- fd’s changelog, useful when an option you read about behaves differently in your version.
- Regular expression syntax from the Rust
regexcrate, the engine fd’s patterns use. - modern-unix, a list of newer command-line tools that pair with fd, such as ripgrep, bat, and fzf.
Related Content
- Learn Zsh covers globbing and glob qualifiers, the shell’s own way to match files.
- Learn Nushell shows a shell that lists files as tables you can filter and sort.
- What Is fzf? explains the fuzzy finder that reads fd’s output to pick files interactively.
- What Is Zoxide? explains a smarter
cdfor jumping to folders you visit often.
Related Articles by Category
🎓 Learn X
Begin learning new software frameworks, languages, tools, and techniques then leave with resources for further study.
💻 Software Engineering
The art and science of creating software applications and systems.
- 1000 Life Giving Potions - Operating System Wildlife
- A List of Pragmatic Programmer Principles
- A List of Software Engineering Blogs: Tech Company Engineering Blogs
- A Software Fundamentals Glossary
- Are We There Yet Development
- Fundamental Algorithmic Patterns
- Fundamental Data Structures
- Fundamental Skills
- All 85 in Software Engineering →

Comments #