skip to content

fd β€” Fast File Finder

Modern find replacement written in Rust. Simpler syntax, respects .gitignore, supports regex and glob patterns, parallel execution, and coloured output.

4 min read 12 snippets 2d ago quick read

fd β€” Fast File Finder#

Installation#

sudo apt install fd-find          # Debian/Ubuntu  (binary: fdfind)
sudo dnf install fd-find          # Fedora/RHEL
brew install fd                   # macOS
cargo install fd-find             # cargo

# Ubuntu alias: add to ~/.bashrc
alias fd=fdfind

Basic usage#

fd pattern               # search by name in cwd (regex by default)
fd pattern /path/to/dir  # search in specific directory
fd                       # list ALL non-ignored files (like ls -R)
fd -g "*.log"            # glob pattern instead of regex

Pattern matching#

fd 'config\.ya?ml'       # regex: config.yaml or config.yml
fd -g "*.{py,rb}"        # glob: .py or .rb files
fd -F "main.c"           # fixed string (no regex)
fd -i "readme"           # case-insensitive
fd "^test_" src/         # anchored to start of filename

Filter by type#

fd -t f pattern          # files only
fd -t d pattern          # directories only
fd -t l pattern          # symlinks only
fd -t x pattern          # executable files
fd -t e pattern          # empty files/dirs

Filter by extension#

fd -e py                 # Python files
fd -e ts -e tsx          # TypeScript files (multiple -e)
fd -e log /var/log/      # .log files in /var/log

Hidden and ignored files#

fd -H pattern            # include hidden (dot) files
fd -I pattern            # no-ignore: don't respect .gitignore
fd -HI pattern           # hidden + no-ignore
fd --no-ignore-vcs       # ignore VCS rules only

Depth control#

fd -d 1 pattern          # max depth 1 (immediate children)
fd -d 3 pattern          # max depth 3
fd --min-depth 2 pattern # skip top-level matches

Size and time filters#

fd -S +1M                # files larger than 1 MB
fd -S -100k              # files smaller than 100 KB
fd -S +1G /var           # files larger than 1 GB

fd --changed-within 1d   # modified in last 24 hours
fd --changed-within 1w   # modified in last week
fd --changed-before 30d  # older than 30 days
fd --changed-before 2024-01-01  # before a specific date

Execute actions#

fd -e log -x rm {}              # delete all .log files
fd -e jpg -x convert {} {.}.png  # convert each jpg β†’ png
fd -e py -X wc -l               # pass ALL results at once to wc

# {} placeholders
# {}    full path
# {/}   filename only
# {//}  parent directory
# {.}   path without extension
# {/.}  filename without extension

Practical examples#

# Find all Python files and run flake8
fd -e py -X flake8

# Find files modified today and copy to backup
fd --changed-within 24h -t f -x cp {} /backup/{}

# Find and delete all __pycache__ directories
fd -t d __pycache__ -X rm -rf

# Find all .env files (hidden, not gitignored normally)
fd -HI -g ".env*"

# Find large video files
fd -e mp4 -e mkv -e mov -S +500M -x du -sh {}

# Rename: add timestamp prefix to all .log files
fd -e log -x mv {} "$(date +%Y%m%d)_{/}"

# Find all symlinks pointing to non-existent targets
fd -t l -x sh -c '[ ! -e "$1" ] && echo "$1"' _ {}

# Count files by extension
fd -t f | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -20

# Find the largest files under a directory
fd -t f -S +1M --no-ignore | xargs du -sh | sort -rh | head -20

Output options#

fd pattern --absolute-path      # print absolute paths
fd pattern -0 | xargs -0 ...    # NUL-delimited (safe for spaces)
fd pattern --color never        # disable colour
fd pattern --one-file-system    # don't cross mount points
fd --list-details               # ls-style long output
fd --follow                     # follow symlinks during traversal

Exclude paths#

fd pattern -E "*.min.js"        # exclude glob
fd pattern -E ".git"            # exclude directory
fd pattern -E "node_modules" -E "dist"  # multiple excludes

fd vs find equivalents#

findfd
find . -name "*.py"fd -e py
find . -type f -name "*.log"fd -t f -e log
find . -type d -name __pycache__fd -t d __pycache__
find . -mtime -1fd --changed-within 1d
find . -size +1Mfd -S +1M
find . -name "*.sh" -exec chmod +x {} \;fd -e sh -x chmod +x {}
find . -not -path "./.git/*"fd -E ".git"

[!TIP] fd respects .gitignore, .fdignore, and .ignore files. Add a global ignore file at ~/.config/fd/ignore (same gitignore syntax) to permanently skip things like node_modules.