你已经安装了 `fzf`。接下来怎么办?(2023)

Lobsters Hottest 工具

摘要

本文提供了一份实用指南,介绍如何最大限度地利用 `fzf` 模糊查找工具来提高生产力,展示了其与 shell 命令、`vi` 和 `ripgrep` 的集成,以实现高效的文件和命令搜索。

<p><a href="https://lobste.rs/s/b6fyzj/so_you_ve_installed_fzf_now_what_2023">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/05/10 16:53

# 所以你已经安装了 `fzf`。接下来呢? - 首先试试 Ctrl+R... (https://andrew-quinn.me/fzf#first-try-ctrlr) - ... 现在试试 Alt+C (https://andrew-quinn.me/fzf#-now-try-altc) - 基础的 fzf 命令 (https://andrew-quinn.me/fzf#the-base-fzf-command) - 但是试试 vi $(fzf),然后...!!! (https://andrew-quinn.me/fzf#but-try-vi-fzf-and) - vi $(find . '/' | fzf):用于查找随机配置文件 (https://andrew-quinn.me/fzf#vi-find----fzf-for-finding-random-config-files) - 更少的摩擦:vi ** (https://andrew-quinn.me/fzf#even-less-friction-vi-tab) - mv $(fzf) $(fzf) - 真正的失忆时刻 (https://andrew-quinn.me/fzf#mv-fzf-fzf---real-amnesiac-hours) - 介绍 rg:快速、默认递归的 grep (https://andrew-quinn.me/fzf#introducing-rg-fast-recursive-by-default-grep) - rg . | fzf:对每个文件中的每一行进行模糊搜索 (https://andrew-quinn.me/fzf#rg---fzf-fuzzy-search-every-line-in-every-file) - rg . | fzf | cut -d ":" -f 1:对每个文件中的每一行进行模糊搜索,并返回文件位置 (https://andrew-quinn.me/fzf#rg---fzf--cut--d---f-1-fuzzy-search-every-line-in-every-file-and-return-the-file-location) - vim $(rg . | fzf | cut -d ":" -f 1):对每个文件中的每一行进行模糊搜索,并打开该文件 (https://andrew-quinn.me/fzf#vim-rg---fzf--cut--d---f-1-fuzzy-search-every-line-in-every-file-and-open-that-file) 软件工程师们,如果不说是独特的话,那么在创造工具以改善自己专业生活的便利性方面,可以说是相当*独特*的;然而,对于那些在不同工具之间不断穿梭而不投入时间去深入学习自己所用工具的人来说,这随着时间的推移可能会带来高昂的代价。作为一个对我认为比我更优秀的人的隐性知识(https://commoncog.com/how-to-learn-tacit-knowledge/)抱有健康尊重的人,我认为一个很好的 80/20 启发式方法是“先学习老家伙们”:像 `cat`、`ls`、`cd`、`grep` 和 `cut` 这样 venerable(受人尊敬的)Unix 工具。(如果你有幸身处一个真正的现代系统管理员角色中,还包括 `sed` 和 `awk`。)但有一些工具的回报如此即时,其价值主张如此独特,以至于 80/20 启发式方法对它们完全失效。`fzf` 就是其中之一。看到许多人下载它,在命令行上原样运行,然后只是摇头走开,说“我不明白”,这让我感到难过。在这里,我想改变这种情况。 假设你生活在一个大致标准的 Ubuntu 机器上。你刚刚使用标准安装脚本(https://github.com/junegunn/fzf#using-git)安装了 `fzf`——那么接下来呢? ## 首先试试 `Ctrl+R`... 在大多数终端中,无论是 Linux 还是 Windows,`Ctrl+R` 都会为你提供命令的*反向搜索*。之所以你像我一样,可能在已经在 shell 中折腾了*整整十年*之后才听说这个功能,是因为基础版本因为两个原因而有点糟糕: - 你需要给出**完全匹配**才能得到你想记住的内容。 - 你只能得到**一个预览**,所以如果你甚至漏掉了一个字符,你就会陷入无休止的搜索。 `fzf` 是一个有点奇怪的程序,因为安装它(https://github.com/junegunn/fzf#using-git)实际上会覆盖一堆键盘快捷键,目的是让它们变得更好。通常情况下我会讨厌这一点。但是... 这比基线有了*显著*的改进。(请注意,通过像 `apt` 这样的包管理器安装 `fzf` **可能不会给你这个功能**!我不断暗示你应该使用安装脚本(https://github.com/junegunn/fzf#using-git),即使你和我都同意 `curl | bash` 是 Super Moloch 的作品!) ## ... 现在试试 `Alt+C` 假设你启动了一个空终端。你试图快速找到你新兴的 SaaS 副业仓库并 `cd` 到那里——但是几周前你就没再去过,你的全职工作异常有趣和吸引人……你如何找到它? 答案:使用 `fzf`。`fzf` 将 `Alt+C` 重写为一个增强的模糊 `cd` 快捷方式,当你只记得相关目录的模糊名称时,可以让你*非常*快速地跳转。 ## 基础的 `fzf` 命令 好吧,我们已经解决了快捷键的问题。老实说,仅这两个家伙就提供了我从 `fzf` 中获得的大多数价值——但是让我们看看命令本身做了什么。 它模糊查找文件位置!至少是相对于你自己目录的位置。这……本身并不是特别有用。 ### 但是试试 `vi $(fzf)`,然后...!!! 你得到了一个在编辑器中模糊打开的体验!(在这方面,`vi` 并没有什么特别之处,顺便说一句。你可以用 `emacs`、`nano`(https://ariadne.space/2021/08/13/gnu-nano-is-my-editor-of-choice/)、`code` 来调用它,无论你喜欢什么!) ## `vi $(find . '/' | fzf)`:用于查找随机配置文件 前几天我正试图结合 Firefox 扩展、`entr` 和 `nginx` 来实现婴儿的第一个实时重载。然后我发现自己在问:`nginx.conf` 到底在哪里? 我回顾了我的选项。我可以 1. 使用我对 FHS 的半记忆知识,通过 `trees` 和 `grep`s 进行猜测,或者 2. 仅仅知道并牢记于心,觉得自己比别人优越,或者 3. 只是将 `find . '/'` 管道到 `fzf` 并开始搜索。 我喜欢这段剪辑,因为它展示了使用 `fzf` 的一些细微权衡,以及一个更高级的搜索功能——搜索 `conf$` 将过滤掉任何不以 `conf` 结尾的行。注意当 `find` 遇到大量“Permission denied”错误时,`fzf` 暂时会失控——但几秒钟后它会恢复过来。为了能够以如此简单的方式找到配置文件,这几秒钟的额外时间是否值得?对我而言是值得一的。 ## 更少的摩擦:`vi **` *感谢 sigmonsays, Hacker News (https://news.ycombinator.com/item?id=35249935),提醒我注意这个功能!* 介于“覆盖键盘快捷键”和“原样使用 fzf”之间的是**使用两个星号进行模糊选项卡补全**。以下是使用它来做类似于上面 `vi $(fzf)` 的事情: 你*确实*需要在实际获得命令后再按一次 `Enter`,特此警告。我还没有养成经常使用这个的习惯,有几个原因。首先,它在某种程度上与我的*真实* home shell(https://fishshell.com/)不兼容,尽管在 bash 和 zsh 中它完全没问题。其次,我在家中唯一的实际用例是作为 `$(fzf)` 的替代品,我只是觉得显式调用男孩更容易记住。我想象这对于 tab-tab-star-headers 来说类似于看着我同事手动从终端复制粘贴而不是使用 `:read ! echo "Hello world!"`(https://knowyourmeme.com/photos/1196921-damn-bitch-you-live-like-this)。 ## `mv $(fzf) $(fzf)` - 真正的失忆时刻 当你既不完全记得你要移动什么,也不记得你要移动到哪里,但你足够记得抽象概念的时间距离,知道它必须完成,并且对每个要转移的项目的性质有*极其具体*的记忆时。 我有点不好意思承认当我试图将 GIF 插入我的 Github READMEs(https://github.com/hiAndrewQuinn/finstem#interactive-mode)时,我有多频繁地使用这个。 ## 介绍 `rg`:快速、默认递归的 `grep` 下面我说的一切*可以*用 `grep` 完成,但 `rg`(也称为 `ripgrep`)的默认递归性质是工具真正发挥效力的地方。我强烈建议你下载它并在下面的示例中使用它。但如果你担心工具太多,别担心! ## `rg . | fzf`:对每个文件中的每一行进行模糊搜索 现在我们进入了一些*真正*失忆的领域 >:3c。 ## `rg . | fzf | cut -d ":" -f 1`:对每个文件中的每一行进行模糊搜索,并返回文件位置 ## `vim $(rg . | fzf | cut -d ":" -f 1)`:对每个文件中的每一行进行模糊搜索,并打开该文件

相似文章

dmtrKovalenko/fff

GitHub Trending (daily)

fff 是一个快速、抗拼写错误的文件搜索工具包,采用 frecency 排序并配备面向 AI 代理的 MCP 服务器,提供高效的、具备 Git 感知的文件与内容搜索功能。

vi 家族

Hacker News Top

本文对 vi 系列文本编辑器及其衍生克隆版本进行了历史回顾和分类整理,涵盖了从 1977 年的原始版本到 Vim 等现代衍生版本。

# 引导 Zig Fmt 在过去的几个月里,我一直在研究 Zig 格式化工具(`zig fmt`)的演变方向,最终形成了[这份提案](https://github.com/ziglang/zig/issues/20078)。由于这是一个颇具争议的话题,我想在这篇文章中详细阐述其中的权衡考量。 ## 现状 `zig fmt` 是一个固执己见的格式化工具:它会将 Zig 代码格式化为单一的规范形式,且不受用户配置的影响。这类工具(如 `gofmt`、`prettier`)有一个显著优势:当整个生态系统都使用同一格式化工具时,就能消除围绕风格的无谓争论,并确保所有代码的外观一致。 然而,现有的 `zig fmt` 存在一个问题:它实际上并不是完全固执己见的——格式化结果会根据用户的输入而变化。 以下面这个例子为例: ```zig const x = foo(1, 2, 3); ``` 如果你在最后一个参数后面加上一个逗号: ```zig const x = foo(1, 2, 3,); ``` `zig fmt` 会将其格式化为: ```zig const x = foo( 1, 2, 3, ); ``` 这意味着代码的格式化方式(单行还是多行)取决于用户是否添加了尾随逗号。此外,`zig fmt` 对于其他一些构造也并非完全固执己见,例如注释的位置。 ## 问题所在 为什么这是个问题呢?毕竟,根据尾随逗号来决定格式化方式,这是一种广为人知且合理的约定。 问题在于,这种方案实际上给了用户两种选择:单行格式和多行格式。这意味着用户必须做出决定,而这恰恰是格式化工具本应消除的那类决策。 更糟糕的是,这个决定并没有一个客观正确的答案,因为适合单行还是多行,往往取决于行的长度——而行的长度会随着变量名、参数等的变化而改变。 举个例子,假设你有: ```zig const x = foo(1, 2, 3); ``` 这段代码很短,放在一行完全没问题。但如果函数名变长了呢? ```zig const x = a_longer_function_name(1, 2, 3); ``` 还是挺短的。那如果更长呢? ```zig const x = a_much_much_longer_function_name(argument_one, argument_two, argument_three); ``` 这行已经相当长了,或许应该换成多行格式: ```zig const x = a_much_much_longer_function_name( argument_one, argument_two, argument_three, ); ``` 但在当前的 `zig fmt` 机制下,你需要手动添加尾随逗号来触发这个格式化。如果你重构代码,将函数名改短,或者把参数替换为更短的名称,那么多行格式可能就不再必要了——但 `zig fmt` 不会自动帮你切换回单行格式,因为它会把尾随逗号视为"保持多行"的明确指令。 ## 解决方案 解决方案是让 `zig fmt` 基于行长度自动决定使用单行还是多行格式。具体来说:如果一个表达式能放在一行内(不超过某个长度限制,比如 100 个字符),就使用单行格式;否则,使用多行格式。 这正是 `prettier` 的工作方式,也是大多数现代格式化工具所采用的方案。 这意味着尾随逗号将不再具有语义上的格式化含义。你可以写: ```zig const x = foo(1, 2, 3,); ``` `zig fmt` 会根据行长度自动决定使用哪种格式,而不是盲目地遵循尾随逗号的指示。 ## 争议点 这项改动之所以有争议,主要有以下几个原因: **1. 人们习惯了现有的行为** 很多 Zig 开发者已经习惯于用尾随逗号来控制格式化。改变这一行为会打破他们的工作流程。 **2. 基于行长度的格式化可能产生令人惊讶的结果** 当你重命名一个变量,导致某行超过了长度限制,整个表达式的格式可能会突然从单行变成多行。这种"蝴蝶效应"可能让人感到困惑。 **3. 需要确定合适的行长度限制** 100 个字符?80 个字符?这本身也是一个需要决策的问题,尽管它只是一次性的决策,而不是每次写代码都要面对的决策。 ## 结论 尽管存在争议,我认为基于行长度的自动格式化是正确的方向。它让 `zig fmt` 真正成为一个固执己见的格式化工具,消除了用户需要做出的格式化决策,并确保代码在重构后始终保持最优的格式。 这与 Zig 语言的整体设计哲学是一致的:减少不必要的复杂性,让工具为开发者做出明智的决策,从而让开发者能够专注于真正重要的事情。

Lobsters Hottest

# 两个让 `zig fmt` 更好用的技巧 Zig 配备了一个内置的代码格式化工具 `zig fmt`。与其他语言的格式化工具不同,`zig fmt` 是"可操控的"——某些语法结构会影响格式化的输出结果。本文将介绍两个实用技巧。 ## 技巧一:尾随逗号控制布局 `zig fmt` 会根据是否存在尾随逗号来决定参数的排列方式。 **没有尾随逗号**时,格式化工具会尝试将所有参数放在同一行: ```zig const result = myFunction(argument1, argument2, argument3); ``` **有尾随逗号**时,格式化工具会将每个参数单独放在一行: ```zig const result = myFunction( argument1, argument2, argument3, ); ``` 这个规则同样适用于函数定义的参数列表、结构体字段、枚举变体等场景。 ```zig // 单行:无尾随逗号 const Point = struct { x: f32, y: f32 }; // 多行:有尾随逗号 const Point = struct { x: f32, y: f32, }; ``` 这意味着你可以通过添加或删除尾随逗号来主动控制格式化的输出,而不必与格式化工具"博弈"。想要多行展示?加上尾随逗号。想要单行展示?去掉它。 同样的逻辑也适用于换行符。如果你在参数之间手动添加了换行符,`zig fmt` 会尊重这个选择并保留多行格式——前提是同时带有尾随逗号。 ## 技巧二:数组的列式格式化 对于数值数组,`zig fmt` 支持一种特殊的列式格式化方式,非常适合用来表示矩阵或表格数据。 只需在数组元素之间手动插入换行符,`zig fmt` 就会将数据对齐成整洁的列式布局: ```zig // 格式化前(你写的) const matrix = [_]f32{ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }; ``` ```zig // 格式化后(zig fmt 输出) const matrix = [_]f32{ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }; ``` `zig fmt` 会识别出你在每行放置了相同数量的元素,并将各列对齐,使代码更具可读性。这对于表示变换矩阵、查找表或任何具有内在行列结构的数据来说极为方便。 ```zig // 一个更直观的例子:查找表 const sine_table = [_]f32{ 0.000, 0.174, 0.342, 0.500, 0.643, 0.766, 0.866, 0.940, 0.985, 1.000, 0.985, 0.940, 0.866, 0.766, 0.643, 0.500, }; ``` ## 小结 `zig fmt` 的"可操控"设计哲学让格式化工具成为你的合作伙伴,而不是独裁者: - **尾随逗号** → 强制多行展开 - **无尾随逗号** → 允许单行折叠 - **手动换行 + 统一列数** → 触发列式对齐 掌握这两个技巧,你就能在享受自动格式化便利的同时,保留对代码视觉呈现的精确控制。