阅读信息
- 内容类型:教程
- 难度:入门
- 适合谁:希望在 Linux、WSL2 与远程服务器上提升命令行效率的开发者。
- 读完后:用 fd 按名称、扩展名、类型、路径和隐藏状态查找文件,并安全地把结果交给其他命令。
- 依据版本:fd 10.5.0
- 验证日期:2026-09-11
find 的语法是在向内核文件系统表达逻辑谓词:
find . -type f -iname '*trace*'在日常开发场景中,读者的真实需求通常只是“在当前工程里找到某个文件”:
fd trace
fd trace src
fd -e cppfd 把日常交互改写为贴近直觉的默认值:默认并行遍历目录树、将搜索词作为正则表达式匹配文件名、跳过隐藏项并自动遵守 .gitignore。这些默认行为显著减少了日常敲击命令的摩擦,但它并不试图覆盖 find 的全部能力。权限掩码、时间戳精确区间、inode 检索以及 POSIX 兼容脚本,依然属于 find 的工作领地。
本文核验版本为 fd 10.5.0。在 Ubuntu 24.04 与 Debian 系列发行版中,安装名和命令调用存在历史包名差异。

1. 安装与命令名解析#
在 Debian 与 Ubuntu 官方仓库中,由于同名软件的历史冲突,软件包被命名为 fd-find:
sudo apt install fd-find安装后,系统提供的可执行文件通常命名为 fdfind:
fdfind --version若希望使用标准的 fd 命令名,不要直接在 /usr/bin 中创建系统级软链接以防覆盖系统未来包。若 ~/.local/bin 已包含在当前用户的 PATH 环境变量中,推荐创建用户级软链接:
mkdir -p ~/.local/bin
ln -s "$(command -v fdfind)" ~/.local/bin/fd在终端中核验命令解析与版本:
command -v fdfind
command -v fd
fd --version如果使用官方独立二进制包、Cargo 编译安装(cargo install fd-find)或 mise/asdf 等版本管理器,通常会直接安装上游命令名 fd。本文后续统一使用 fd 进行说明。
2. 参数结构与核心搜索维度#
参数模型:[pattern] 与 [path]…#
理解 fd 的关键在于掌握其参数位置模型:
fd [OPTIONS] [pattern] [path]...第一个非选项参数始终被解析为 pattern(匹配模式),后续参数才被解析为搜索根路径 path。如果没有指定搜索路径,默认在当前工作目录递归搜索。
常见错误是在指定扩展名搜索特定目录时省略 pattern:
fd -e json research/modern-cli/fixture这会触发错误提示:
[fd error]: The search pattern 'research/modern-cli/fixture' contains a path-separation character and will not lead to any search results.原因在于 fd 将 research/modern-cli/fixture 识别为了模式,而默认情况下模式只与文件名(basename)比对。当模式包含路径分隔符 / 时必须明确告知 fd 意图:使用 . 表示匹配任意文件名的模式,或者通过 --search-path 显式声明根路径:
# 推荐:使用 '.' 作为任意匹配模式,随后指定目录
fd -e json . research/modern-cli/fixture
# 或者使用长选项显式指定路径
fd -e json --search-path research/modern-cli/fixture在测试夹具中执行输出:
research/modern-cli/fixture/data/results.json模式匹配:正则、固定字符串与 Glob#
fd 默认使用正则表达式匹配文件名。若查找包含特殊符号的纯文本文件名,使用 -F(--fixed-strings):
fd -F 'config[old]'若习惯通配符形式,可以使用 -g(--glob):
fd -g '*.toml'如果需要模式匹配包含目录结构的完整路径,加上 -p(--full-path):
fd -p 'research/.*/results\.json'扩展名与条目类型#
指定文件扩展名无需手动书写正则前缀:
fd -e cpp
fd -e yaml -e yml
fd trace -e cpp注意:-e 过滤只检查名称末尾是否符合扩展名,如果某个目录恰好以 .json 结尾,也会被匹配出来。若仅需要匹配普通文件,应配合 -t f 显式限定类型:
fd -t f -e json . research/modern-cli/fixture常用类型选项包括:
-t f(--type file):普通文件;-t d(--type directory):目录;-t l(--type symlink):符号链接;-t x(--type executable):可执行文件;-t e(--type empty):空文件或空目录。
大小写敏感度#
fd 默认采用 smart case 策略:
- 搜索模式全为小写时,执行大小写不敏感搜索;
- 搜索模式中只要包含任意大写字符,自动切换为大小写敏感搜索。
需要强制控制时:
fd -i readme # 强制忽略大小写(匹配 README.md, readme.txt)
fd -s README # 强制区分大小写(仅匹配大写 README)隐藏文件与 Ignore 规则的分层#
fd 默认跳过两类条目:
- 隐藏文件与隐藏目录(以
.开头); - 被
.gitignore、.ignore、.fdignore或全局 gitignore 规则匹配的路径。
放宽过滤条件需要区分两者的边界:
-H(--hidden):包含隐藏项,但依然严格遵守 ignore 规则;-I(--no-ignore):不遵守 ignore 规则,但依然跳过隐藏项;-u(--unrestricted):等价于-H -I,同时搜索隐藏项和被 ignore 的文件。
在测试夹具中验证分层过滤:
# 只开启隐藏项,能搜到 .env.example,但排除被 gitignore 的 generated.txt
fd -H env research/modern-cli/fixture
# 忽略 ignore 规则,能搜到 build/generated.log 与 ignored/generated.txt
fd -I generated research/modern-cli/fixture
# 两者均放开
fd -u generated research/modern-cli/fixture如需在放宽过滤后针对特定目录排除噪声,可以使用 -E(--exclude,支持多次指定):
fd -H -E .git -E node_modules -E target config3. -x 与 -X:逐项并行与批量执行#
fd 内置了类似 find -exec 的执行机制,分为 -x(--exec)与 -X(--exec-batch)两种截然不同的执行模型。
-x(逐项执行)#
-x 为检索出的每个目标分别调用一次外部命令。默认情况下,fd 会利用多核 CPU 并行派发进程:
fd -e sh . research/modern-cli/fixture -x wc -l执行模型等价于:
wc -l research/modern-cli/fixture/script.sh
wc -l research/modern-cli/fixture/expected/check-quoted.sh
wc -l research/modern-cli/fixture/src/check.sh因为并行执行且顺序无序,绝对不能依赖前一个文件的执行输出作为后一个文件的前置条件。若需要顺序逐项执行,必须显式限制线程数:--threads=1。
-X(批量执行)#
-X 把所有检索出的候选文件汇总,作为参数一次性传递给外部命令(类似于 xargs):
fd -e sh . research/modern-cli/fixture -X wc -l执行模型等价于:
wc -l file1.sh file2.sh file3.sh终端实际输出:
5 research/modern-cli/fixture/src/check.sh
8 research/modern-cli/fixture/script.sh
5 research/modern-cli/fixture/expected/check-quoted.sh
18 totalwc -l 只启动了一次,并输出了合计行数 18 total。如果候选数量超过系统单条命令长度上限,fd 会自动切分为多批执行,也可以通过 --batch-size <NUM> 手动指定批次大小。
占位符与参数终止陷阱#
在 -x 与 -X 中可以使用结构化占位符:
{}:完整相对路径(例如src/utils/calc.py);{/}:基本文件名(basename,例如calc.py);{//}:所在父目录(例如src/utils);{.}:去除扩展名的路径(例如src/utils/calc);{/.}:去除扩展名的基本文件名(例如calc)。
若未书写任何占位符,fd 会在命令末尾自动追加 {}。
重要参数陷阱: 命令行中紧跟在 -x 或 -X 之后的所有参数都会被解释为外部命令的组成部分,而不再是 fd 的参数。
例如若将搜索根目录放在 -X 之后:
# 错误写法:fixture 目录会被当作 wc 的待读取文件
fd -e sh -X wc -l research/modern-cli/fixture这会导致 fd 在当前目录搜索所有 .sh 文件,同时把 research/modern-cli/fixture 传递给 wc 处理报错。正确的做法是将目录放在 -X 前面,或者使用 \; 明确结束命令模板:
# 正确写法 1:将搜索根放在 -X 之前
fd -e sh . research/modern-cli/fixture -X wc -l
# 正确写法 2:用分号转义结束外部命令模板
fd -e sh -X wc -l research/modern-cli/fixture \;在执行具有破坏性修改的操作(如删除、覆盖)前,务必先用无副作用命令预览候选清单:
fd -e tmp . -x printf '待清理文件: %s\n' {}确认匹配边界安全后,再切换为真正的动作命令。
4. 与 rg、fzf 组合时的文件名边界#
在 Unix 系统中,换行符、空格与破折号是合法的文件名字符。构建自动化流水线时必须防范文件名注入与路径解析截断。
与 ripgrep 组合#
fd 专注于找文件,rg 专注于搜文本。二者通过 -X 联动兼具速度与精确度:
fd -e py . research/modern-cli/fixture -X rg -n 'def '相比 rg --glob,这种方式可以借助 fd 的类型筛选、空文件排除和动态条件灵活圈定目标集。
与 fzf 交互联动#
通过管道将结果交给 fzf 进行交互式选择:
fd -t f | fzf当文件树可能包含空格或换行等特殊字符时,标准换行分隔会导致下游工具切词错误。稳健的处理方案是全程采用 NUL(\0)字节流协议:
fd -t f -0 | fzf --read0 --print0注意:fd 在使用 -0、-x 或 -X 时,默认会在相对路径前保留 ./ 前缀,以防以连字符 - 开头的文件名被下游工具误认为是命令参数。如果传递给 fzf 希望展示更干净的相对路径,可以使用 --strip-cwd-prefix。
5. 工具分工:fd、find 与 locate 的场景边界#
fd 并不能也不应该完全淘汰 find 或 locate,三者解决不同的工程问题:
| 对比维度 | fd | find | locate |
|---|---|---|---|
| 核心机制 | 多线程实时遍历,默认 ignore | 单线程实时遍历文件系统谓词 | 查询预建数据库(updatedb) |
| 性能特征 | 本地 SSD 项目树极快 | 中等,受单线程与 POSIX 约束 | 全盘秒级返回,非实时 |
| 默认行为 | 忽略隐藏文件与 .gitignore | 遍历一切路径,不跳过任何文件 | 依赖数据库最近更新状态 |
| 适用场景 | 开发者在代码库与日常目录交互 | 运维审计、复杂逻辑判断、POSIX 脚本 | 在全系统跨多盘查找未知文件 |
必须使用 find 的场景#
当涉及复杂的文件系统元数据、POSIX 脚本规范或系统审计时,应当坚决使用 find:
# 按最后修改时间(30天前)、文件大小(>100M)与属主精确筛选
find /var/log -type f -mtime +30 -size +100M -user root
# 按八进制权限位匹配并执行安全删除
find /tmp -type f -perm 0777 -exec rm -f {} +使用 locate(如 plocate / mlocate)的场景#
需要在整台主机的数十万目录中寻找某个系统库或头文件,且可以接受索引更新存在延迟时,locate 无需遍历磁盘,速度远高于任何实时搜索工具:
locate libssl.so6. 运行资源、故障排查与防护#
fd 是无守护进程(daemonless)的纯命令行工具,进程退出后立即释放全部内存与句柄。但在特定环境下需要注意系统资源开销:
- 并行 I/O 压力:
fd默认根据 CPU 核心数启动线程并发扫描。在本地 NVMe SSD 上性能优异;但在机械硬盘(HDD)、NFS 网络存储或 WSL2 挂载的宿主机盘符(如/mnt/c)上,大量并发跨目录寻道会导致 I/O 抖动。此时应使用-j 1(--threads=1)限制并发线程。 - 避免越过文件系统挂载点:在根目录
/下搜索时,应配合--one-file-system防止扫描意外深入到挂载的远程网络卷或只读快照中。 - 控制遍历深度:在大型依赖树(如 monorepo 或深度嵌套目录)中,使用
-d 3(--max-depth 3)设置搜索深度上限。
搜不到目标时的排查清单#
当 fd 未返回预期文件时,按以下顺序排查:
- 参数解析顺序:检查是否因遗漏 pattern 而把目录当成了搜索词(是否应写
fd . <path>); - 大小写敏感:检查搜索词是否包含大写字母触发了 smart case;
- 隐藏文件:目标路径或其父目录是否以
.开头(尝试添加-H); - 忽略规则拦截:目标是否被当前或上级
.gitignore、.ignore、.fdignore排除(尝试添加-I); - 类型或扩展名限制:是否叠加了
-t f但目标是软链接或目录,或-e拼写错误; - 模式语法:当前模式是正则还是纯文本(包含
[、+等符号时尝试添加-F)。
绝不要在系统 Shell 配置中设置 alias fd='fd -u'。无条件关闭 ignore 与隐藏过滤会把 node_modules、构建缓存和临时索引重新注入搜索结果,破坏 fd 设计的初衷。
7. 最小可复现练习#
在测试夹具目录 research/modern-cli/fixture 中执行以下命令,验证对各类条件与执行模型的理解:
# 1. 查找指定目录下的所有 json 文件(注意使用 . 占据 pattern 位置)
fd -e json . research/modern-cli/fixture
# 2. 搜索隐藏文件并限定为普通文件(查看 .env.example)
fd -H -t f env research/modern-cli/fixture
# 3. 忽略 ignore 规则搜索构建产物
fd -I generated research/modern-cli/fixture
# 4. 仅检索目录条目
fd -t d . research/modern-cli/fixture
# 5. 检索所有 shell 脚本并批量统计行数(验证 -X 的参数传递)
fd -e sh . research/modern-cli/fixture -X wc -l完成练习后,应能清楚解释:命令中各个参数的位置含义、默认过滤规则何时生效,以及外部命令 -x 与 -X 的启动次数与风险控制。
参考资料#
本文采用 CC BY-NC-SA 4.0 许可。