## 前言 今天我们介绍一个命令行模糊搜索神器 fzf(Fuzzy Finder),它可以用来搜索文件、文件夹、历史记录、内容搜索、进程等等,如果你还没有用过它,我强烈推荐你去尝试一下,非常好用。 官方文档:https://github.com/junegunn/fzf 下面我们就来安装 fzf,介绍一些常用操作以及如何与 zsh 集成配置,掌握这些可以提供很大的工作效率。 ## 安装 fzf ```bash brew install fzf ``` 安装成功之后,命令行输入 `fzf` 默认应该是这样的。 ![fzf default](https://cdn.nlark.com/yuque/0/2025/png/1863084/1751775534689-75b60592-e10b-4f5a-bd88-74e2fcafb9b8.png?x-oss-process=image%2Fformat%2Cwebp) 现在就可以在终端通过模糊匹配来搜索文件了,`` 或者 `` 切换上下匹配项,`` 选中,`` 取消。 官方文档也给出了对应的搜索语法,比较简单,大家感兴趣的可以看下。 | Token | Match type | Description | |-----------|-------------------------------------------|--------------------------------------------------| | `sbtrkt` | fuzzy-match | Items that match `sbtrkt` | | `'wild` | exact-match (quoted) | Items that include `wild` | | `'wild'` | exact-boundary-match (quoted both ends) | Items that include `wild` at word boundaries | | `^music` | prefix-exact-match | Items that start with `music` | | `.mp3$` | suffix-exact-match | Items that end with `.mp3` | | `!fire` | inverse-exact-match | Items that do not include `fire` | | `!^music` | inverse-prefix-exact-match | Items that do not start with `music` | | `!.mp3$` | inverse-suffix-exact-match | Items that do not end with `.mp3` | ## fzf 与 zsh 集成 ### 基础配置 > 如果你是通过 brew 安装的,默认会生成对应的配置 fzf 可以与 zsh 集成,使得搜索体验更加顺滑,只需要在 `~/.zshrc` 文件中添加以下配置: ```bash source <(fzf --zsh) ``` 使用 fd 替换默认的 find 命令,可以提高搜索效率。 ```bash export FZF_DEFAULT_COMMAND="fd --hidden --strip-cwd-prefix --exclude .git" # Use fd (https://github.com/sharkdp/fd) for listing path candidates. # - The first argument to the function ($1) is the base path to start traversal # - See the source code (completion.{bash,zsh}) for the details. _fzf_compgen_path() { fd --hidden --follow --exclude ".git" . "$1" } # Use fd to generate the list for directory completion _fzf_compgen_dir() { fd --type d --hidden --follow --exclude ".git" . "$1" } ``` ### 文件和文件夹搜索配置 ```bash export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" export FZF_ALT_C_COMMAND="fd --type=d --hidden --strip-cwd-prefix --exclude .git" ``` 启用集成后,你可以使用以下快捷键: - `Ctrl+T`:搜索文件并插入到命令行 - `Alt+C`:搜索目录并切换 - `Ctrl+R`:搜索命令历史(默认集成) ### 预览配置 需要安装 bat 和 eza 两个工具,bat(cat 的增强) 用来预览文件内容,eza(ls 的增强) 用来展示文件目录树。 ```bash brew install bat eza ``` 通过 bat 预览文件内容,eza 展示文件目录树。 ```bash show_file_or_dir_preview="if [ -d {} ]; then eza --tree --color=always {} | head -200; else bat -n --color=always --line-range :500 {}; fi" export FZF_CTRL_T_OPTS="--preview '$show_file_or_dir_preview'" export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'" ``` 配置之后我们看下效果 `` 文件搜索 ![文件搜索](https://cdn.nlark.com/yuque/0/2025/png/1863084/1751781455674-18f18e57-398e-4152-b101-27f4d00bc3c3.png?x-oss-process=image%2Fformat%2Cwebp) `` 文件夹搜索 ![文件夹搜索](https://cdn.nlark.com/yuque/0/2025/png/1863084/1751781211467-b8f67bd0-bf7b-4493-a8a3-57b047347957.png?x-oss-process=image%2Fformat%2Cwebp) `` 命令历史搜索 ![命令历史搜索](https://cdn.nlark.com/yuque/0/2025/png/1863084/1751782160703-d81f0b95-c414-446e-a410-29580b0effbd.png?x-oss-process=image%2Fformat%2Cwebp) ### 文件内容搜索 通过 rg 实现文件内容搜索,并使用 fzf 进行预览,绑定 `` 快捷键进行搜索。 ```bash # file content search fif() { if [ ! "$#" -gt 0 ]; then echo "Need a string to search for!"; return 1; fi rg --files-with-matches --no-messages "$1" | fzf --preview '$show_file_or_dir_preview' } find-in-file() { grep --line-buffered --color=never -r "" * | fzf } zle -N find-in-file bindkey '^f' find-in-file ``` 使用 `Ctrl + F` 搜索文件内容 ![文件内容搜索](https://cdn.nlark.com/yuque/0/2025/png/1863084/1751783125287-ab2c6131-ed64-49c2-be90-ea2bbda60a9f.png?x-oss-process=image%2Fformat%2Cwebp) ## 其他功能 1. 命令行输入 cd `` 默认会触发 fzf。 2. 多选模式:` + 选中项` 选中,``` + + 选中项``` 取消选中。可以使用 vim 打开多个选中的文件。 3. `kill -9 ` fzf 也可以用来搜索进程。 4. `vim ** ` ** 也可以触发 fzf。 5. 与 Git 结合、与 Vim 结合等。 ## 最后 本文介绍了 fzf 的安装以及与 ZSH 集成的相关配置,包括文件搜索、文件夹搜索、命令历史搜索、文件内容搜索、预览配置等核心功能,相信如果从头到尾跟着配置之后,你会发现 fzf 真的是非常好用。当然 fzf 还有很多其他的功能,可以自行通过官方文档更进一步的学习。 如果你喜欢看视频,参考资料部分也有非常好的视频教程,大家可以去学习。 最后附上完整的 fzf 配置文件 ```bash # ---- FZF ----- # Set up fzf key bindings and fuzzy completion source <(fzf --zsh) # -- Use fd instead of fzf -- export FZF_DEFAULT_COMMAND="fd --hidden --strip-cwd-prefix --exclude .git" export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" export FZF_ALT_C_COMMAND="fd --type=d --hidden --strip-cwd-prefix --exclude .git" # use fzf replace default shell search # export FZF_CTRL_R_OPTS='--no-sort --exact' # Use fd (https://github.com/sharkdp/fd) for listing path candidates. # - The first argument to the function ($1) is the base path to start traversal # - See the source code (completion.{bash,zsh}) for the details. _fzf_compgen_path() { fd --hidden --exclude .git . "$1" } # Use fd to generate the list for directory completion _fzf_compgen_dir() { fd --type=d --hidden --exclude .git . "$1" } show_file_or_dir_preview="if [ -d {} ]; then eza --tree --color=always {} | head -200; else bat -n --color=always --line-range :500 {}; fi" export FZF_CTRL_T_OPTS="--preview '$show_file_or_dir_preview'" export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'" # file content search fif() { if [ ! "$#" -gt 0 ]; then echo "Need a string to search for!"; return 1; fi rg --files-with-matches --no-messages "$1" | fzf --preview '$show_file_or_dir_preview' } find-in-file() { grep --line-buffered --color=never -r "" * | fzf } zle -N find-in-file bindkey '^f' find-in-file # Advanced customization of fzf options via _fzf_comprun function # - The first argument to the function is the name of the command. # - You should make sure to pass the rest of the arguments to fzf. _fzf_comprun() { local command=$1 shift case "$command" in cd) fzf --preview 'eza --tree --color=always {} | head -200' "$@" ;; export|unset) fzf --preview "eval 'echo \${}'" "$@" ;; ssh) fzf --preview 'dig {}' "$@" ;; *) fzf --preview "$show_file_or_dir_preview" "$@" ;; esac } ``` ## 学习资料 - 官方文档:[https://github.com/junegunn/fzf](https://github.com/junegunn/fzf) - 不错的视频教程: - [https://www.youtube.com/watch?v=mmqDYw9C30I&t=383s](https://www.youtube.com/watch?v=mmqDYw9C30I&t=383s) - [https://www.bilibili.com/video/BV1fdTfzeE8X/](https://www.bilibili.com/video/BV1fdTfzeE8X/)