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#
| find | fd |
|---|---|
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 -1 | fd --changed-within 1d |
find . -size +1M | fd -S +1M |
find . -name "*.sh" -exec chmod +x {} \; | fd -e sh -x chmod +x {} |
find . -not -path "./.git/*" | fd -E ".git" |
[!TIP]
fdrespects.gitignore,.fdignore, and.ignorefiles. Add a global ignore file at~/.config/fd/ignore(same gitignore syntax) to permanently skip things likenode_modules.