公司动态
终端效率革命:用fd、fzf、bat和rg打造极速文件搜索与代码定位流水线
这个秘密我其实不太愿意写出来。不是因为它见不得光而是因为它太“小”了——小到很多同行就算知道了也只会觉得“就这”。但它确实让我在日常开发里省下了大量来回切换窗口、反复找文件、凭记忆翻路径的时间。如果你和我一样每天大部分时间耗在项目代码、配置文件和日志输出之间这套东西值得你花一个下午搭起来然后一直用下去。我所说的“秘密”不是某个新出的 AI 编程工具也不是什么高深算法而是四个成名已久的命令行小工具fd、fzf、bat、rg再加上几个写在 shell 配置里的自定义函数。单独看它们每一个都不稀奇但把它们按特定顺序串起来就会变成一套覆盖“找文件、看内容、搜代码、跳目录、做批量处理”的终端流水线。真正拉开效率差距的不是某个工具本身而是这套组合方式。1. 这个“秘密”其实是把四件小事串成一条流水线1.1 为什么单看每个工具都不稀奇先说fd它本质上是find的替代品但默认行为更贴近直觉。find需要写-name *.pyfd直接写fd -e py就能按扩展名过滤。它默认忽略.gitignore里的文件和隐藏目录所以在项目里搜文件时不会把node_modules和target里的内容翻出来。再说fzf它是一个通用模糊查找工具。最常用的场景是把一堆文件路径通过管道喂给它然后你用键盘上下选择按回车输出选中的那一项。和 IDE 里的“CtrlP”跳转文件有点像但它不限于编辑器任何命令的输出都能接上去。然后是bat它是cat的增强版主要价值是给文件内容加上语法高亮还能显示行号。如果你只把它当cat用那确实不值得单独装但在下面这条流水线里它是“预览”环节的关键。最后是rg也就是ripgrep一个极快的递归搜索工具。它比grep快很多而且默认尊重.gitignore不搜二进制文件。对于“在某个目录下搜索某段文本”这个高频操作它是目前我最常用的答案。1.2 真正值钱的是调用顺序和组合方式这四个工具单独拎出来每个都有大量教程没什么可隐瞒的。但它们真正发挥威力是在一条这样的流水线里fd -t f | fzf --preview bat --coloralways {}这条命令的意思是先列出当前项目下所有文件再通过fzf进行模糊筛选选中某个文件时用bat在预览窗口里高亮显示它的内容回车后输出文件路径。如果你还想直接打开这个文件可以再接一层fd -t f | fzf --preview bat --coloralways {} | xargs -r vim这一串命令其实是在模仿一个很底层的逻辑先定位再预览最后执行。它把“在文件树里一层层点开”这种线性操作变成了“输入关键词-模糊匹配-预览确认-直接执行”的并行操作。后者不需要你记忆文件在哪个目录只需要记得文件名里的几个关键词就行。而这套组合真正的进阶用法是把rg也接进来先用rg搜索代码里的某个符号再把搜索结果喂给fzf筛选最后跳到具体文件行号。这样你就不需要先猜文件再去文件里找行号而是直接从“内容”出发一步到位。2. 先跑通一条最小工作流找文件、看内容、进目录2.1 用 fd 替代 find 找文件如果你还没有安装这几个工具先装一下。在 macOS 上如果使用 Homebrewbrew install fd fzf bat ripgrep在 Linux 上可以用对应的包管理器比如 apt 或 dnfWindows 上如果有 scoop 或 choco也都有现成包。装完之后先试试最基础的文件查找fd -t f -e md这个命令会列出当前目录下所有 Markdown 文件。-t f表示只找文件不找目录-e md表示扩展名是 md。如果你在一个大型仓库里执行会明显感觉到fd几乎没有停顿。常用参数可以这样理解-t d只看目录适合快速看清项目结构。-H包含隐藏文件比如.env或.gitignore。-g *.log用通配符匹配文件名。--full-path匹配完整路径而不是仅文件名。fd还有一个很实用的特性它默认会读取.gitignore所以不会把node_modules、target、dist这些目录带进来。这是我认为它比find更值得日常使用的最重要原因。2.2 用 fzf 做模糊筛选fzf的用法不复杂你把标准输出喂给它它会启动一个交互式界面让你输入关键词然后从所有行里做模糊匹配。例如fd -t f | fzf运行之后界面底部会出现一个输入框输入readme列表会实时过滤。回车后被选中的那一行会打印到终端。你可以在脚本里拿到这个结果也可以直接把它接给下一个命令。我建议先不要急着接触高级配置只需理解它的三个核心机制模糊匹配输入rdm也能匹配到README.md不需要连续字符串。预览窗口通过--preview参数指定一条命令用来展示当前候选行的详情。输出默认把选中的结果打印到 stdout方便管道传递。下面是一个带预览的文件选择器fd -t f | fzf --preview bat --coloralways {}这里的{}代表当前被选中的文件路径。--coloralways是为了让bat在高亮模式下输出即使它通过管道传给fzf时也保留颜色。2.3 用 bat 高亮预览bat本身非常好理解bat README.md它会显示带行号、带语法高亮的内容。配合fzf时我们需要让它只输出预览不进入分页模式。--coloralways是保证颜色传输会有一个分页器的问题。你可以在预览命令里再加上--pagingneverfd -t f | fzf --preview bat --coloralways --pagingnever {}这样在fzf的预览区域里文件内容会以高亮形式展示而且不会出现less的分页交互。如果你想让预览窗口更宽或更高可以用--preview-windowright:60%这类参数调整。2.4 三个命令串成一条快速打开流程现在把这三个工具串起来定义成一个 shell 函数以后输入一个ff就能直接调用ff() { local file file$(fd -t f | fzf --preview bat --coloralways --pagingnever {}) if [[ -n $file ]]; then vim $file fi }把这个函数写进~/.bashrc或~/.zshrc重载配置后你只需要在项目目录里输入ff就能在本目录下快速找文件并打开。如果你用 Neovim也可以把vim改成nvim。这里有一个很关键的习惯先让单条命令跑通再固化成函数。不要一上来就写一堆复杂配置否则遇到问题时根本不知道是哪一环坏了。3. 把“搜内容”也加进来rg 与 fzf 的联动3.1 rg 的基本用法rg的核心用法是rg 关键字它会在当前目录下递归搜索所有文本文件输出匹配的行、行号和文件路径。常用的补充参数-l只列出包含匹配内容的文件名不输出具体行。-i忽略大小写。-g *.py只搜索 Python 文件。--type py效果类似但使用内置类型定义。-n显示行号通常默认就开启。-w全词匹配避免搜log时把blog也带出来。如果你的项目变量名拼写没记全只记得包含某个单词rg -l加fzf是我最常用的组合。3.2 让 fzf 接管结果预览当你从大量文件中搜出匹配内容后往往还需要逐个查看上下文。你可以这样做rg -l FunctionName | fzf --preview bat --coloralways --pagingnever {}这条命令会先列出所有包含FunctionName的文件然后让你用模糊筛选选一个文件接着在预览窗口看到该文件的内容。但这样还看不到具体是哪个位置命中的。如果想在预览里直接看到匹配行周围的上下文可以稍微绕一下rg -n FunctionName | fzf --preview echo {} | cut -d: -f1 | xargs bat --coloralways --pagingnever -H $(echo {} | cut -d: -f2)这个命令比较长我先拆一下rg -n输出格式是文件路径:行号:内容。把整行传给fzf后选中的结果也包含路径和行号。预览命令先把{}按冒号拆成两段拿到路径和行号再调用bat -H 行号来高亮那一行。如果你觉得这条命令太长可以把它简化成一个函数并且不追求一步到位。对于大多数场景先用rg -n 关键字 | fzf能拿到目标行的原始文本然后再按下回车把它打印出来配合编辑器跳转会更容易理解。3.3 常见参数理解-l、--type、-g在实际项目中搜索范围控制非常重要。rg默认已经排除了.gitignore指定的目录但如果你需要跨多个指定目录搜索可以写rg -l TODO src tests docs如果只想搜某类文件两种常见写法rg -l TODO -g *.py -g *.js或者使用内置类型rg -l TODO --type py --type ts区别在于-g更灵活可以写复杂通配符--type更语义化不需要记扩展名。但--type对某些自定义扩展名可能没有内置规则这时-g更好用。另外一个容易被忽视的参数是--hidden它会让rg搜索隐藏文件。这在查.env或.gitignore内容时很关键。不过默认不搜索隐藏文件是更安全的行为至少不会突然把大量缓存文件带进搜索范围。4. 真正拉开差距的不是命令而是工作习惯4.1 把高频操作固化成 shell 函数工具只是零件真正让效率起飞的是习惯和封装。我一般会把自己最常用的三四个操作写成~/.zshrc里的函数每个函数只做一件事命名短且好记。比如上面的ff是“找文件并编辑”我还会写一个fg是“搜索代码并打开文件”fg() { local selected selected$(rg -l $1 | fzf --preview bat --coloralways --pagingnever {}) if [[ -n $selected ]]; then vim $selected fi }这里的$1是你传入的关键字比如fg UserService就会先搜索所有包含UserService的文件再让你选择并打开。还有fd定位到目录、然后直接cd过去fcd() { local dir dir$(fd -t d | fzf --preview ls -la {}) if [[ -n $dir ]]; then cd $dir fi }这三个函数分别对应三种高频动作找文件、找代码、跳目录。如果你能坚持使用一个礼拜肌肉记忆会逐渐形成。4.2 从单次执行到批量操作的场景当这些命令能稳定运行时你可以进一步把它们用进批量操作里。例如想找出所有包含DEBUG_LOG的 Python 文件然后批量打印文件的最后修改时间rg -l DEBUG_LOG --type py | xargs ls -lt或者把所有包含FIXME的文件路径输出到一个列表文件供后续审查rg -l FIXME fixme_list.txt这里要注意xargs处理和带空格的文件名时容易出问题。如果项目路径里有空格更稳妥的方式是使用-0配合fd的-0参数或者直接用while read循环。在实际工作中文件名含空格的情况不少所以我一般会这样写rg -l FIXME -0 | xargs -0 -n1 ls -lt-0让rg用空字符分隔文件名xargs -0也按空字符解析这样就不会被空格拆开。这个细节虽然小但能避免很多不必要的坑。4.3 如何一步步培养终端直觉不要想着一次性掌握所有参数。我建议按这个顺序来先只学fd -t f、fzf --preview、bat、rg 关键字四个基本命令。每两天往 shell 函数里加一个小参数比如-i忽略大小写或-w全词匹配。遇到需要“翻目录找文件”时强制自己回终端用fzf不要打开文件树。遇到需要“全局搜索某个字符串”时先想rg而不是 IDE 的全局搜索快捷键。这种训练的本质是把“路径记忆”转成“内容记忆”。过去你要记住“文件在哪个目录下”现在你只需要记住“文件里大概有什么、文件名叫什么”。对于大型项目和我这种记性一般的人来说这是一次认知减负。5. 避坑指南环境差异、性能边界和排查链路5.1 安装和依赖Linux/macOS/Windows这几个工具的安装一般都很顺利但有几个环境相关的问题容易踩macOS 上bat的--coloralways预览可能会闪退通常是因为终端颜色类型不支持或 locale 环境有问题。可以先试export TERMxterm-256color或者把预览命令改成bat --pagingnever --decorationsalways。Linux 上如果fzf预览窗口里有乱码大概率是终端编码和bat的主题配置不匹配可以设置BAT_THEMEansi作为临时验证。Windows 环境如果你使用 Git Bash 或 WSL大部分命令可以直接跑。原生 cmd 和 PowerShell 下fd可能有fd.exe和fdfind的命名差异Debian/Ubuntu 系安装的包叫fdfind需要在 shell 配置里加一个别名alias fdfdfind。这些不算什么大问题但如果在配置阶段不解决很容易让人误以为是工具本身不好用而放弃。5.2 性能边界项目太大时怎么降级当你在一个几十万文件的巨型仓库里使用fd -t f | fzf时第一次列出所有文件可能会有肉眼可见的延迟。这时候不要硬扛有几个降级策略先进入子目录再执行命令缩小范围。用-g限定目录比如fd -t f -g src/**。把--preview去掉只做筛选减少开预览窗口的 IO。用rg --files替代fd -t f在某些场景下rg --files同样很快而且和rg的 ignore 规则一致。另外fzf本身默认会在输入关键词时重新过滤文件数量极大时建议设置--bindctrl-r:reload之类的按需加载但这对新手来说有点复杂。更简单的方法是先缩小项目目录再进入工作流。5.3 排查思路按现象、输入、环境、参数、工具边界逐层检查如果你在组合使用中遇到问题不要急着怀疑工具而是按这个顺序排查看现象是命令报错、没有输出还是预览窗口空白看输入当前目录是否有你预期的文件是否有隐藏目录是否用了相对路径看环境这几个工具是否装齐shell 是否重新加载了配置是否用了别名冲突看参数--preview里的命令是否为完整路径{}是否被正确转义--coloralways是否让预览片段无法解析看工具边界这个文件是否在.gitignore里是否二进制文件是否超出了rg默认的文件编码支持范围举个例子如果你执行rg 中文没结果先别怀疑rg对中文支持不好。它默认会尝试 UTF-8如果你的文件是 GBK 编码自然搜不到。这时可以用rg --encoding gbk 中文来指定编码或者先把文件转成 UTF-8。大多数组合命令的问题最后都能定位到“输入路径不对”或“参数没有正确传到预览命令”这两类原因上而不是工具本身坏了。6. 这个“秘密”的适用边界别盲目上瘾6.1 适合谁、不适合谁这套工作流最适合的是日常在终端里工作并且需要频繁切换文件、搜索代码的人比如后端开发、运维、数据分析师、独立开发者。如果你已经习惯 IDE 的全局搜索、文件树和插件系统这套命令不会带来颠覆性改变但能补上 IDE 对“跨多个项目”“批量操作”“极轻量预览”这些场景的短板。它不适合的场景也很明确如果你的工作几乎都在集成开发环境里完成而且项目结构很稳定不太需要频繁跳转那么花时间配置这些工具反而会增加不必要的负担。另外如果你已经重度依赖 VS Code 的 Remote、Workspace 等能力也没有必要强行切换到终端。我的建议是可以在一个中等规模的开源项目上先试用一周不要迁移到生产主项目。等确认手感合适再逐步养成习惯。6.2 和 IDE 的关系是互补不是替代这套终端工作流不是用来替代 IDE 的。它擅长的是“快速定位文件、快速预览内容、快速执行批量命令”但真正的复杂重构、断点调试、可视化 Diff 等还是需要 IDE 或者专门的编辑器。你完全可以在终端里用fzf找到文件然后用code命令在 VS Code 中打开它fd -t f | fzf --preview bat --coloralways {} | xargs code这其实才是很多人的最佳组合用终端做检索和跳转用 IDE 做深度编辑。不要把两者对立起来它们分别处理不同层级的任务。6.3 长期沉淀把它变成自己的配置和脚本很多教程会直接让你复制粘贴一大段 dotfiles 配置但我更建议你从零开始每个函数都亲手写一遍并且理解每一行在做什么。这样你遇到边界情况时才有能力调整。当你的配置稳定下来后可以考虑做这几件事把函数和别名整理到单独的~/.config/mycli/目录按主题拆分比如fzf.zsh、rg.zsh。把常用项目目录加入fzf的搜索范围实现跨项目快速跳转。把预览命令替换成更适合你语言生态的高亮工具比如用glow预览 Markdown用jq预览 JSON。为fzf配置快捷键绑定比如Ctrl-T粘贴文件路径、Ctrl-R增强历史搜索。这一整套沉淀下来才是属于你自己的“秘密”。它不会再是四个工具的组合而是被你的工作方式反复打磨后的私人工具链。如果你也想搭一套不必追求和我完全一样。先复制最小可用入口再根据实际需求慢慢加东西。今天可以先试试fd -t f | fzf --preview bat --coloralways {}这一条看看你每天要打开的那些文件是否真的都能用一个命令快速定位到。如果能那这个“秘密”就算开始起效了。