随风逐叶 随风逐叶
首页
  • Quick Reference (opens new window)
  • EgretEngine开发者文档 (opens new window)
  • TinaX框架
  • SSH教程
  • VSCode插件开发
关于
  • 分类
  • 标签
  • 归档

rontian

从事游戏开发10多年的老菜鸟一枚!
首页
  • Quick Reference (opens new window)
  • EgretEngine开发者文档 (opens new window)
  • TinaX框架
  • SSH教程
  • VSCode插件开发
关于
  • 分类
  • 标签
  • 归档
  • macOS fzf 完全指南:从安装配置到 Git、代码搜索与高级交互
    • 1. 安装 fzf
    • 2.1 现代推荐配置
    • 2.2 如果以前已经使用 ~/.fzf.zsh
      • 不要重复加载两套 integration
    • 3.1 Ctrl-T:文件选择
    • 3.2 Ctrl-R:搜索历史命令
    • 3.3 Alt-C / Option-C:搜索目录并 cd
    • 4.1 验证 Option-C 实际发送什么
    • 4.2 iTerm2 推荐设置
    • 4.3 这个设置会影响什么?
    • --with-nth
    • --nth
  • Mac上使用brew安装nvm来支持多版本的Nodejs
  • 让Mac应用的「崩溃报告」不再烦人
  • MacOs Shell 修改替换文件字符串
  • MacOS安装RubyGame
  • 使用HomeBrew和jEnv进行Java多版本管理
  • Mac shell使用技巧总结
  • macos rsync 选项说明
  • MacOS
rontian
2026-09-24
目录

macOS fzf 完全指南:从安装配置到 Git、代码搜索与高级交互

# macOS fzf 完全指南:从安装配置到 Git、代码搜索与高级交互

如果你经常在 macOS 上使用 iTerm2、zsh、Git、Vim/Neovim 或各种 CLI 工具,那么 fzf 基本属于非常值得配置的一类终端工具。

很多人第一次接触 fzf,只把它理解成“模糊搜索文件”。实际上更准确的理解是:

fzf 是一个通用的终端交互式选择器。

它可以把几乎任何命令产生的文本列表变成一个支持搜索、预览、多选、快捷键和动作绑定的终端 UI。

它的核心工作模型可以理解为:

任意命令产生候选数据
        ↓
       fzf
        ↓
搜索 / 筛选 / 预览 / 多选
        ↓
输出选择结果 / 执行动作
1
2
3
4
5
6
7

例如:

printf '%s\n' apple banana orange | fzf
1

也可以是:

git branch | fzf
ps aux | fzf
fd --type f | fzf
rg "Player" | fzf
1
2
3
4

本文以 macOS + iTerm2 + zsh 为主要环境,并以现代 fzf 0.74.x 的功能为基础。


# 1. 安装 fzf

macOS 推荐直接使用 Homebrew:

brew install fzf
1

建议顺手安装几个经常和 fzf 配套使用的工具:

brew install fd ripgrep bat eza
1

它们分别负责:

工具 用途
fzf 交互式模糊选择器
fd 文件、目录搜索,通常比传统 find 更适合交互使用
ripgrep / rg 高性能代码内容搜索
bat 带语法高亮的文件预览
eza 更现代的目录列表和目录树显示

安装后确认版本:

fzf --version
1

截至 2026-09-24,Homebrew 中的稳定版本为 0.74.4。


# 2. zsh Shell Integration

fzf 不只是一个单独执行的命令,它还可以集成到 zsh 中,提供快捷键和 **<Tab> 补全。

# 2.1 现代推荐配置

现代版本可以直接在 ~/.zshrc 中加入:

source <(fzf --zsh)
1

然后重新加载:

source ~/.zshrc
1

它会提供:

Ctrl-T      文件/目录选择
Ctrl-R      历史命令搜索
Alt-C       目录搜索并 cd
**&lt;Tab>     fuzzy completion
1
2
3
4

# 2.2 如果以前已经使用 ~/.fzf.zsh

一些较早版本的 fzf 安装脚本会生成:

~/.fzf.zsh
1

并在 ~/.zshrc 里加入:

[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
1

这种配置并不代表已经失效。

只要它仍然正常加载 fzf 的 completion 和 key bindings,就完全可以继续使用。

检查:

bindkey | grep fzf
1

如果类似:

"^I" fzf-completion
"^R" fzf-history-widget
"^T" fzf-file-widget
"^[c" fzf-cd-widget
1
2
3
4

说明已经完整加载:

Ctrl-I / Tab    → fzf completion
Ctrl-R          → history
Ctrl-T          → file
Alt-C           → cd
1
2
3
4

# 不要重复加载两套 integration

如果旧配置已经工作,不建议同时再写:

[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
source <(fzf --zsh)
1
2

否则可能出现重复注册 completion 或 widget 的情况。

可以继续保留旧方式;以后如果想清理配置,再统一迁移到:

source <(fzf --zsh)
1

即可。


# 3. 三个最常用快捷键

# 3.1 Ctrl-T:文件选择

在当前命令行里按:

Ctrl-T
1

fzf 会打开文件/目录选择界面,并把选择结果插入当前命令行。

例如先输入:

vim 
1

然后按:

Ctrl-T
1

选择:

src/components/PlayerView.ts
1

最后命令行会变成:

vim src/components/PlayerView.ts
1

这个快捷键特别适合:

vim
nvim
code
cat
bat
open
cp
mv
rm
1
2
3
4
5
6
7
8
9

等需要输入路径的命令。


# 3.2 Ctrl-R:搜索历史命令

按:

Ctrl-R
1

可以通过 fzf 搜索 shell history。

相比传统 shell 的单条历史搜索,fzf 的优势是:

  • 可以同时看到多条候选
  • 支持模糊匹配
  • 支持多关键词
  • 可以快速重复很久以前执行过的命令

例如搜索:

docker compose
1

可以快速找到之前执行过的相关命令。


# 3.3 Alt-C / Option-C:搜索目录并 cd

fzf 默认绑定:

Alt-C
1

选择目录后直接执行:

cd <selected-directory>
1

在 macOS 上,这个快捷键非常容易遇到一个问题:

fzf 已经绑定成功,但 Option-C 没有触发。

先检查:

bindkey | grep fzf
1

如果已经看到:

"^[c" fzf-cd-widget
1

说明 fzf 本身没有问题。

^[c 的意思就是:

ESC + c
1

即终端里的 Alt-C / Meta-C。

问题通常来自 iTerm2 的 Option 键设置。


# 4. macOS / iTerm2 中配置 Option 为 Alt / Meta

macOS 的 Option 键默认主要用于输入特殊字符。

例如:

Option-C
1

可能输入:

ç
1

但终端程序期望收到的是:

ESC + c
1

也就是:

^[c
1

# 4.1 验证 Option-C 实际发送什么

在 iTerm2 中:

先按 Ctrl-V
再按 Option-C
1
2

如果显示:

ç
1

说明 Option 被 macOS 用作特殊字符输入。

如果显示类似:

^[c
1

则说明已经正确作为 Meta/Alt 发送。


# 4.2 iTerm2 推荐设置

打开:

iTerm2
→ Settings
→ Profiles
→ Keys
1
2
3
4

找到:

Left Option key
Right Option key
1
2

推荐设置:

Left Option  → Esc+
Right Option → Normal
1
2

这样:

左 Option
    ↓
终端 Alt / Meta
    ↓
fzf / Vim / zsh / TUI 快捷键
1
2
3
4
5

而:

右 Option
    ↓
继续保留 macOS 原生特殊字符输入
1
2
3

这是比较平衡的一种设置。


# 4.3 这个设置会影响什么?

如果把左 Option 设置成 Esc+,那么:

Left Option + C
Left Option + B
Left Option + F
Left Option + D
...
1
2
3
4
5

都会变成终端的 Meta/Alt 组合键。

这不会影响:

Cmd-C
Cmd-V
Ctrl-C
Ctrl-R
Ctrl-T
Shift
1
2
3
4
5
6

真正改变的是该侧 Option 键的特殊字符输入行为。

这通常反而会让很多 CLI 软件里的:

Alt-B
Alt-F
Alt-J
Alt-K
Alt-C
Alt-Enter
1
2
3
4
5
6

等快捷键开始正常工作。


# 5. **<Tab>:fzf fuzzy completion

shell integration 还提供了 fuzzy completion。

例如:

vim **<Tab>
1

会打开文件选择。

搜索目录:

cd **<Tab>
1

父目录:

vim ../**<Tab>
1

Home:

vim ~/**<Tab>
1

指定前缀:

vim ../texture**<Tab>
1

还可以配合某些命令,例如:

ssh **<Tab>
1

甚至:

kill **<Tab>
1

具体 completion 行为会根据命令不同而有所区别。


# 6. fzf 基础使用模型

最简单:

fzf
1

如果没有显式输入源,现代 fzf 可以使用自己的 walker 来生成候选文件。

更常见的是通过管道:

command | fzf
1

例如:

printf '%s\n' apple banana orange | fzf
1

选择结果会输出到 stdout。

因此可以:

selected=$(printf '%s\n' apple banana orange | fzf)

echo "$selected"
1
2
3

这也是很多自定义 CLI 脚本的基础。


# 7. fzf 查询语法

fzf 不只是普通 substring search,它支持扩展搜索语法。

常用形式:

查询 含义
abc 模糊匹配
'abc 精确包含
^abc abc 开头
abc$ abc 结尾
!abc 排除 abc
abc def AND
abc \| def OR

例如:

.ts$ player !test
1

表示:

.ts 结尾
AND
包含 player
AND
不包含 test
1
2
3
4
5

特别适合大型代码仓库。


# 8. 默认界面配置

fzf 默认可以全屏打开,不过个人更推荐类似下拉面板的形式。

可以在 ~/.zshrc 中配置:

export FZF_DEFAULT_OPTS="
  --height=70%
  --layout=reverse
  --border
  --info=inline
  --cycle
"
1
2
3
4
5
6
7

之后所有普通 fzf 调用都会继承。

这里:

--height=70%       占当前终端高度 70%
--layout=reverse   输入框和结果从顶部开始
--border           显示边框
--info=inline      状态信息内联
--cycle            上下选择可以循环
1
2
3
4
5

注意:不要为了省事把所有参数都塞到 FZF_DEFAULT_OPTS。

例如 --ansi、--nth、--with-nth 都可能增加解析成本,更适合按具体功能单独使用。


# 9. 为 Ctrl-T 增加文件预览

如果已经安装:

brew install bat eza
1

可以:

export FZF_CTRL_T_OPTS="
  --walker-skip .git,node_modules,dist,build,target
  --preview '
    if [ -d {} ]; then
      eza --tree --level=2 --color=always {}
    else
      bat --style=numbers --color=always --line-range=:500 {}
    fi
  '
  --bind 'ctrl-/:change-preview-window(down|hidden|)'
"
1
2
3
4
5
6
7
8
9
10
11

效果是:

  • 当前项是目录:右侧显示目录树
  • 当前项是文件:右侧使用 bat 显示代码
  • Ctrl-/:切换 preview 布局或隐藏 preview

# 10. 为 Alt-C 增加目录树预览

export FZF_ALT_C_OPTS="
  --walker-skip .git,node_modules,dist,build,target
  --preview 'eza --tree --level=2 --color=always {}'
"
1
2
3
4

以后按:

Alt-C
1

选择目录时可以同时预览里面的结构。


# 11. Preview:fzf 最重要的高级功能之一

例如:

fd --type f |
fzf --preview 'bat --color=always --style=numbers {}'
1
2

可以把 fzf 变成一个简单的文件浏览器。

调整 preview 大小:

fd --type f |
fzf \
  --preview 'bat --color=always --style=numbers {}' \
  --preview-window=right,60%
1
2
3
4

绑定快捷键切换 preview:

fd --type f |
fzf \
  --preview 'bat --color=always {}' \
  --bind 'ctrl-/:change-preview-window(right|hidden|)'
1
2
3
4

# 12. 多选模式

启用:

fzf --multi
1

或:

fzf -m
1

常见操作:

Tab        选择当前项目
Shift-Tab  取消/反向移动
Enter      确认
1
2
3

例如选择多个文件:

fd --type f | fzf -m
1

这也是用 fzf 编写 Git commit picker、批量文件处理器等工具的基础。


# 13. 文件名安全:不要过度依赖简单命令替换

很多示例会写:

vim $(fzf)
1

但文件名如果带空格、换行或特殊字符,可能产生问题。

单文件至少推荐:

file=$(fzf)

[[ -n "$file" ]] && code -- "$file"
1
2
3

需要处理任意文件名、多文件时,可以使用 NUL 分隔:

fd --print0 |
fzf --read0 --print0 --multi |
xargs -0 open
1
2
3

这里:

--read0
--print0
1
2

意味着使用 NUL 而不是换行作为记录分隔符。

对于正式脚本,这是更可靠的方案。


# 14. fd + fzf:文件搜索

基础版本:

fd --type f | fzf
1

带 preview:

fd --type f |
fzf --preview 'bat --color=always --style=numbers {}'
1
2

搜索目录:

fd --type d | fzf
1

Finder 打开:

dir=$(fd --type d | fzf)
[[ -n "$dir" ]] && open "$dir"
1
2

# 15. macOS open + fzf

选择文件后使用默认程序打开:

file=$(fd --type f | fzf)
[[ -n "$file" ]] && open "$file"
1
2

Finder 中定位文件:

file=$(fd --type f | fzf)
[[ -n "$file" ]] && open -R "$file"
1
2

open -R 对 macOS 很实用,它不是直接打开文件,而是在 Finder 中定位并选中文件。


# 16. pbcopy + fzf:复制路径

macOS 自带:

pbcopy
1

可以:

file=$(fd --type f | fzf)

[[ -n "$file" ]] &&
printf '%s' "$file" | pbcopy
1
2
3
4

甚至直接绑定:

fd --type f |
fzf \
  --bind 'ctrl-y:execute-silent(printf %s {} | pbcopy)'
1
2
3

以后在 fzf 中:

Ctrl-Y
1

即可把当前路径复制到剪贴板。


# 17. rg + fzf + bat:代码搜索

这是最经典的组合之一。

rg \
  --color=always \
  --line-number \
  --no-heading \
  --smart-case \
  'Player' |
fzf \
  --ansi \
  --delimiter=: \
  --preview 'bat --color=always --highlight-line {2} {1}'
1
2
3
4
5
6
7
8
9
10

假设 rg 输出:

src/Player.ts:87:class Player
1

那么:

{1} = src/Player.ts
{2} = 87
1
2

所以 preview 可以直接:

bat --highlight-line 87 src/Player.ts
1

# 18. --ansi:处理带颜色的上游输出

如果上游命令产生 ANSI 颜色,例如:

git log --color=always
1

fzf 应使用:

fzf --ansi
1

例如:

git log \
  --color=always \
  --pretty=format:'%C(yellow)%h%Creset %C(cyan)%ad%Creset %s' \
  --date=short |
fzf --ansi
1
2
3
4
5

不要把 --ansi 无脑加入全局配置;只有输入数据确实带 ANSI 颜色时才需要。


# 19. Git Branch Selector

简单版本:

branch=$(
  git branch --format='%(refname:short)' |
  fzf
)

[[ -n "$branch" ]] && git switch "$branch"
1
2
3
4
5
6

增加预览:

branch=$(
  git branch --format='%(refname:short)' |
  fzf \
    --preview 'git log --oneline --graph --decorate --color=always -20 {}'
)

[[ -n "$branch" ]] && git switch "$branch"
1
2
3
4
5
6
7

这样 fzf 就成了一个非常轻量的 Git branch manager。


# 20. Git Commit Browser

git log \
  --color=always \
  --pretty=format:'%C(auto)%h %C(cyan)%ad%Creset %s' \
  --date=short |
fzf \
  --ansi \
  --no-sort \
  --preview 'git show --color=always {1}'
1
2
3
4
5
6
7
8

左侧浏览 commit:

a123abc 2026-09-24 Fix adapter
b456def 2026-09-23 Add selector
1
2

右侧直接查看:

commit 信息
diff
1
2

这里:

{1}
1

表示第一字段,即 commit hash。


# 21. 为什么 Git Log 常用 --no-sort

fzf 默认会按照 fuzzy score 重新排序结果。

但 Git 历史原本就是时间序列:

new
↓
old
1
2
3

因此很多时候使用:

fzf --no-sort
1

更合理。

同样适用于:

  • shell history
  • 日志
  • 时间顺序事件
  • 已经由上游正确排序的数据

# 22. --delimiter、--with-nth、--nth、--accept-nth

这是写高级 fzf CLI 时非常重要的一组参数。

假设输入:

abc123|2026-09-24|rontian|Fix login
def456|2026-09-23|alice|Add UI
1
2

使用:

fzf \
  --delimiter='|' \
  --with-nth=2.. \
  --accept-nth=1
1
2
3
4

其中:

--delimiter='|'
1

定义字段分隔符。

--with-nth=2..
1

控制用户看到哪些字段。

UI 可以只显示:

2026-09-24 | rontian | Fix login
2026-09-23 | alice   | Add UI
1
2

但最终:

--accept-nth=1
1

只返回:

abc123
1

即 commit hash。

这实现了:

内部数据
  ≠
UI 显示数据
  ≠
最终输出数据
1
2
3
4
5

非常适合 Git commit picker。


# 23. --with-nth 和 --nth 的区别

这两个参数很容易搞混。

# --with-nth

控制:

用户看到什么
1

# --nth

控制:

fzf 搜索哪些字段
1

假设数据:

hash | date | author | subject
1

你不希望 hash 出现在 UI,也不希望 hash 参与搜索:

fzf \
  --delimiter='|' \
  --with-nth=2.. \
  --nth=2..
1
2
3
4

但是原始记录依然存在,在 preview/action 中仍然可以:

{1}
1

读取 hash。


# 24. fzf 占位符

在 preview、bind、execute 等场景中,经常使用占位符。

常用:

占位符 含义
{} 当前完整行
{1} 第一字段
{2} 第二字段
{2..} 第二字段直到末尾
{+} 所有已选择项目
{q} 当前查询字符串
{n} 当前结果索引

例如:

printf '%s\n' \
  'abc|rontian|Fix bug' \
  'def|alice|Add UI' |
fzf \
  --delimiter='|' \
  --preview 'echo hash={1}; echo author={2}; echo message={3}'
1
2
3
4
5
6

# 25. --bind:fzf 真正进入高级阶段的地方

fzf 支持把按键和事件绑定到 action。

可以理解为:

Key / Event
    ↓
 Action
1
2
3

例如:

fzf --bind 'ctrl-r:reload(fd)'
1

按:

Ctrl-R
1

重新执行 fd,刷新候选列表。

常用 action:

Action 用途
execute(...) 执行外部程序,结束后回到 fzf
execute-silent(...) 静默执行
become(...) 用新程序替代 fzf 进程
reload(...) 重新加载候选列表
change-prompt(...) 修改 prompt
change-preview-window(...) 修改预览布局
toggle-preview 显示/隐藏 preview
clear-query 清空搜索词

# 26. become():直接进入 Vim / Neovim

传统写法可能是:

fzf | xargs vim
1

现代 fzf 可以:

fzf --bind 'enter:become(vim {})'
1

即:

fzf
 ↓
直接替换成 vim
1
2
3

结合 rg:

rg \
  --line-number \
  --no-heading \
  --color=always \
  'Player' |
fzf \
  --ansi \
  --delimiter=: \
  --preview 'bat --color=always --highlight-line {2} {1}' \
  --bind 'enter:become(vim {1} +{2})'
1
2
3
4
5
6
7
8
9
10

选择:

src/Player.ts:87:...
1

Enter 后直接进入:

vim src/Player.ts +87
1

# 27. 动态 reload

fzf 可以不退出界面,动态刷新数据源。

例如进程列表:

ps -Ao pid,user,%cpu,%mem,command |
fzf \
  --header-lines=1 \
  --bind 'ctrl-r:reload(ps -Ao pid,user,%cpu,%mem,command)'
1
2
3
4

以后:

Ctrl-R
1

即可刷新当前进程列表。

这时候 fzf 已经不只是“搜索工具”,而开始接近一个轻量 TUI 框架。


# 28. 动态 rg:输入内容直接驱动代码搜索

大型项目里,可以让 fzf 本身不负责搜索,而把 query 实时交给 ripgrep。

RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case"

fzf \
  --ansi \
  --disabled \
  --bind "start:reload:$RG_PREFIX {q} || true" \
  --bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
  --delimiter=: \
  --preview 'bat --color=always --highlight-line {2} {1}'
1
2
3
4
5
6
7
8
9

工作流程:

输入 PlayerManager
        ↓
fzf change event
        ↓
rg PlayerManager
        ↓
reload
        ↓
结果返回 fzf UI
1
2
3
4
5
6
7
8
9

这里:

{q}
1

表示当前 query。

sleep 0.1 相当于一个简单 debounce,避免每输入一个字符都快速产生大量中间搜索进程。

大型仓库里,这种结构通常比先把整个代码库搜索结果一次性输给 fzf 更合理。


# 29. 进程选择器

浏览进程:

ps -Ao pid,user,%cpu,%mem,command |
fzf --header-lines=1
1
2

选择 PID:

pid=$(
  ps -Ao pid,user,%cpu,%mem,command |
  fzf --header-lines=1 |
  awk '{print $1}'
)

[[ -n "$pid" ]] && kill "$pid"
1
2
3
4
5
6
7

默认优先普通:

kill
1

不要习惯性所有进程都使用:

kill -9
1

只有普通终止失败时再考虑强制结束。


# 30. 日志流 + fzf

fzf 也可以处理持续产生的数据。

例如:

tail -f server.log |
fzf \
  --tail=100000 \
  --tac \
  --no-sort
1
2
3
4
5

这里:

--tail=100000
1

表示只保留最近一定数量的记录,避免无限日志长期占用越来越多内存。

类似地可以:

docker logs -f container_name |
fzf --tail=100000 --tac --no-sort
1
2

# 31. --tac

--tac 会反转输入顺序。

例如历史记录:

history |
fzf --tac --no-sort
1
2

让较新的内容更靠近当前操作位置。

对于:

  • history
  • logs
  • event stream

都很有用。


# 32. 推荐的 macOS fzf 配置

如果使用现代 shell integration,一份比较实用的配置可以是:

# ------------------------------------------------------------
# fzf
# ------------------------------------------------------------

export FZF_DEFAULT_OPTS="
  --height=70%
  --layout=reverse
  --border
  --info=inline
  --cycle
"

export FZF_CTRL_T_OPTS="
  --walker-skip .git,node_modules,dist,build,target
  --preview '
    if [ -d {} ]; then
      eza --tree --level=2 --color=always {}
    else
      bat --style=numbers --color=always --line-range=:500 {}
    fi
  '
  --bind 'ctrl-/:change-preview-window(down|hidden|)'
"

export FZF_ALT_C_OPTS="
  --walker-skip .git,node_modules,dist,build,target
  --preview 'eza --tree --level=2 --color=always {}'
"

source <(fzf --zsh)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

如果当前仍然使用旧安装方式:

[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
1

则保留这一行即可,不要再重复 source <(fzf --zsh)。

上面的:

FZF_DEFAULT_OPTS
FZF_CTRL_T_OPTS
FZF_ALT_C_OPTS
1
2
3

仍然可以放在加载 ~/.fzf.zsh 之前。


# 33. 推荐的日常使用组合

如果只想掌握最值得使用的一部分,我建议按这个顺序:

Ctrl-T
Ctrl-R
Alt-C
   ↓
**&lt;Tab>
   ↓
--preview
   ↓
--multi
   ↓
fd + fzf
rg + fzf + bat
Git + fzf
   ↓
--delimiter
--with-nth
--nth
--accept-nth
   ↓
--ansi
   ↓
--bind
   ↓
execute
execute-silent
become
reload
   ↓
{1} {2} {q} {+}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

掌握这部分以后,fzf 已经足够覆盖绝大多数日常 CLI 交互场景。


# 34. 最重要的设计思维

不要把 fzf 理解成:

fzf = 文件模糊搜索器
1

更好的模型是:

             Data Source
                 │
       ┌─────────┼─────────┐
       │         │         │
      git       rg        fd
       │         │         │
       └─────────┴─────────┘
                 ↓
             Normalize
                 ↓
                fzf
        ┌────────┼────────┐
      Query    Preview   Multi
        │        │         │
        └────────┼─────────┘
                 ↓
               Action
        ┌────────┼─────────┐
      output   execute    become
                │
              reload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

fzf 最适合负责的是:

交互 UI 和选择。

真正的业务逻辑应该留给:

git
rg
fd
awk
sed
脚本
CLI 程序
1
2
3
4
5
6
7

例如一个 Git commit picker,推荐结构是:

Git 提供 commit 数据
       ↓
脚本整理字段
       ↓
fzf 显示 / 搜索 / 多选 / preview
       ↓
脚本取得真实 commit hash
       ↓
执行 cherry-pick
       ↓
脚本处理冲突状态机
1
2
3
4
5
6
7
8
9
10
11

不要让业务逻辑依赖 fzf 中为了好看而渲染出来的字符串。

尤其在有 ANSI 颜色、作者配色、列对齐和多字段显示时,应该尽量区分:

真实数据
显示数据
搜索数据
返回数据
1
2
3
4

这正是:

--delimiter
--with-nth
--nth
--accept-nth
1
2
3
4

这些参数真正的价值。


# 35. 总结

在 macOS 上,fzf 最值得配置的并不是单独执行:

fzf
1

而是把它融入整个 CLI 工作流:

zsh
 +
fzf
 +
fd
 +
rg
 +
bat
 +
eza
 +
Git
 +
pbcopy
 +
open
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

最终你会得到一套非常统一的交互方式:

文件       → fzf
目录       → fzf
历史命令   → fzf
Git branch → fzf
Git commit → fzf
代码搜索   → fzf
进程       → fzf
日志       → fzf
自定义 CLI → fzf
1
2
3
4
5
6
7
8
9

而且不需要引入一个复杂的重量级 TUI 框架。

对于经常使用终端的 macOS 开发者来说,fzf 真正的价值并不是“搜索得快”,而是:

给任意 CLI 数据源快速增加一个高效、统一、可组合的交互层。


# 参考资料

  • fzf 官方仓库:https://github.com/junegunn/fzf
  • fzf README:https://github.com/junegunn/fzf/blob/master/README.md
  • fzf Advanced Guide:https://github.com/junegunn/fzf/blob/master/ADVANCED.md
  • Homebrew fzf:https://formulae.brew.sh/formula/fzf
上次更新: 2026/09/24, 18:30:05 访问次数: 0
Mac上使用brew安装nvm来支持多版本的Nodejs

Mac上使用brew安装nvm来支持多版本的Nodejs→

最近更新
01
一些Shell常用的功能写法整理
10-20
02
删除git仓库submodule的步骤
10-20
03
django基本命令
10-16
更多文章>
Copyright © 2017-2026 随风逐叶
沪ICP备18008791号-1 | 沪公网安备31011502401077号

网站访问总次数: 0次
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式