通用的Shell命令行模糊查询工具

技术 资源

工欲善其事,必先利其器,常使用Linux命令终端的人都知道,bash默认情况下提供了很多便利的功能,比如TAB命令补全等,CTRL+R命令搜索等,但是这些功能往往有这样或者那样的问题致使不够尽兴。今天,虫虫给大家介绍一款强大通用系统模糊搜索补全工具Fzf,可以给这方面的功能锦上添花,趋于完美。

概述

Fzf是一个开源的交互式shell命令行模糊查询工具,可以用于对文件,历史记录(history),进程,主机名,书签,git commit等等列表和应用。

Fzf是用Golang语言开发的shell系统工具,源代码托管再Github上,截止目前该项目已经累积了25500星,Fork上千。

借助于Golang静态编译的特点,Fzf具有便携式,无依赖性;高性能,速度飞快的优点,同时还具有:

最全面的功能集;

布局灵活;

额外强大的插件支持:

比如Vim/Neovim插件,可支持键绑定和模糊自动补全。

安装

Fzf支持通过Homebrew、操作系统包管理器以及源码方式安装。其文件项目有四部分组成,包括以下组件:

fzf可执行文件;

fzf-tmux脚本,用于在tmux窗格中启动fzf;

Shell扩展:支持按键绑定(CTRL-T,CTRL-R和ALT-C),支持bash,zsh,fish。

模糊自动补全,支持bash,zsh。

Vim/Neovim插件。

其中,fzf可执行文件是必须的,其他组件依赖于它。如果不需要其他组件,可以单独下载fzf可执行文件运行。

发行版包管理器安装

Fzf最简单的安装方法就是通过OS发行版本的包管理器一键安装。Fzf支持了最广泛的发行版本安装:

Arch Linux:

sudo pacman -S fzf

Debian系:

fzf支持Debian Buster及更新的版本,可以使用apt-get包管理器安装。sudo apt-get install fzf

Fedora:

fzf支持Fedora 26及更新的版本,可以使用dnf安装:

sudo dnf install fzf

默认情况下,启用vim或neovim的Shell补全和插件。Shell键绑定已安装,但默认情况下未启用。有关更多信息,请参见Fedora的软件包文档(/usr/share/doc/fzf/README.Fedora)。

FreeBSD:

pkg install fzf

NixOS:

以使用Nix软件包管理器来安装fzf。

nix-env -iA nixpkgs.fzf

openSUSE:

对于openSUSE 支持Tumbleweed版本,可通过zypper安装:

sudo zypper install fzf

Windows:

Windows的预编译二进制文件可以项目发布页下载。fzf也支持以Chocolatey或Scoop软件包管理器安装:

choco install fzf

scoop install fzf

但是,该项目的其他组件可能无法在Windows上运行。已知问题和限制可以在Wiki页面上找到。可能要考虑在Windows子系统(适用于Linux)上安装fzf,以确保一切运行正常。

Homebrew安装

对于Mac系统可以Homebrew fzf。

brew install fzf

如果要安装用键绑定和模糊补全脚本使用:

(brew --prefix)/opt/fzf/install

也可以通过MacPorts:

sudo port install fzf

Git安装

如果你的用的发行版恰好不支持,或者你需要自定义源码安装最新版本,可以通过git clone 克隆项目,然后执行安装程序即可。

git clone --depth 1 github.com/junegunn/fzf.git ~/.fzf

~/.fzf/install

Vim插件

安装好Fzf后,在Vim配置文件中将目录添加到&runtimepath,就可以在Vim启它,如下所示:

" 通过Homebrew安装的

set rtp+=/usr/local/opt/fzf

" 通过git安装的

set rtp+=~/.fzf

如果使用要vim-plug,则配置如下:

"通过Homebrew安装的

Plug '/usr/local/opt/fzf'

"通过git安装的

Plug '~/.fzf'

也可以使用vim-plug来完成安装工作,而不是在系统上单独安装fzf(使用Homebrew或git clone),然后通过配置在Vim中启用(添加到&runtimepath )。

Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }

升级fzf

Fzf在持续迭代开发,为了获取最新功能,则需要时时升级版本。Fzf的升级方法如下:

git安装:

cd ~/.fzf && git pull && ./install

brew:

brew update; brew reinstall fzf

chocolatey: choco upgrade fzf

vim-plug: :PlugUpdate fzf

Fzf源码编译

Fzf编译需要golang 1.11版本以上,还依赖下面的第三方库:

使用的第三方库

mattn/go-runewidth

mattn/ o-shellwords

mattn/go-isatty

tcell

构建fzf二进制文件并将其复制到bin目录,

make && make install

在目标中构建32位和64位可执行文件和tarball

make release

为目标中所有受支持的平台制作发布档案

make release-all

使用go get构建

Fzf也支持,直接通过go get命令,而无需手动克隆存储库。具体命令如下:

go get -u github.com/junegunn/fzf

Fzf用法大全

Fzf安装后,将启动交互式查找程序,从STDIN中读取列表,然后将所选项目写入STDOUT。

find * -type f | fzf > selected

如果没有STDIN管道,则fzf将使用find命令来获取文件列表(不包括隐藏文件)。(可以使用FZF_DEFAULT_COMMAND覆盖默认命令)

vim $(fzf)

使用finder

CTRL-J/CTRL-K(或CTRL-N/CTRL-P)可上下移动光标

输入键选择项目,按CTRL-C/ TRL-G/ESC退出

在多选模式(-m)中,使用TAB和Shift-TAB标记多个项目

Emacs样式键绑定

鼠标:滚动,单击,双击;在多选模式下按住Shift点击并Shift滚动。

布局

默认情况下,Fzf开题全屏模式,我们可以使用--height选项使其在光标下方开始。

vim $(fzf --height 40%)

如果喜欢"自上而下"的布局而不是默认的"自下而上"的布局,请使用--reverse和--layout选项。

vim $(fzf --height 40%)

可以将这些选项添加到$ FZF_DEFAULT_OPTS,以便默认情况下应用它们。例如,

export FZF_DEFAULT_OPTS ='-高度40%--layout = reverse --border'

搜索语法

除非有特殊说明,Fzf都会以扩展搜索模式启动,可以在其中键入多个以空格分隔的搜索词。比如:^music .mp3$ chongchong !fire

相关解释如下:

chongchong模糊匹配,匹配chognchong字条;

^music前缀精准匹配,匹配以music开头的字条;

.mp3$ 后缀精准匹配,匹配以.mp3结尾的字条;

'whild 精准匹配,匹配包含wild的字条;

!fire 反向精准匹配,匹配其中不包含fire的字条;!也支持对前后缀匹配的反向匹配。

上例子表示查找以music开头,以.mp3结尾,不包括fire,含有chongchong的字条。

如果不喜欢模糊匹配并且不想"引用"每个单词,可以用-e或--exact选项启动fzf。注意:设置为--exact时,"-prefix"选项会实效。

单个竖线字符可以充当OR运算符。比如,下面的查询匹配以core开头,以go,rb或py结尾的条目。

^core go$ | rb$ | py$

环境变量

FZF_DEFAULT_COMMAND

输入为tty时使用的默认命令

例如导出FZF_DEFAULT_COMMAND ='fd --type f'

FZF_DEFAULT_OPTS

默认选项

例如export FZF_DEFAULT_OPTS ="-layout = reverse --inline-info"

fzf-tmux脚本

fzf-tmux是一个bash脚本,用来在tmux窗格中打开fzf。

在水平分割中窗体中(15行))显示git分支

git branch | fzf-tmux -d 15

在左侧垂直分割的窗体中(屏幕宽度的20%)显示字典的内容:

cat /usr/share/dict/words | fzf-tmux -l 20% --multi --reverse

如果不是tmux模式,该插件也可以正常工作,只是-[udlr]选项会实效。通常模式下需要使用--height HEIGHT[%]选项,启动非全屏模式的fzf。

fzf --height 40%

命令行的键绑定

安装脚本将会在bash,zsh和fish添加以下按键绑定。

CTRL-T: 将选定的文件或者目录粘贴到命令行上

可通过设置FZF_CTRL_T_COMMAND覆盖默认命令;

可通过设置FZF_CTRL_T_OPTS设置其他选项;

CTRL-R : 从历史记录中将所选命令粘贴到命令行上

如果想按时间顺序查看命令,请再次按CTRL-R,按相关性切换排序

可通过设置FZF_CTRL_R_OPTS设置其他选项;

ALT-C cd进入所选目录

可通过设置FZF_ALT_C_COMMAND以覆盖默认命令;

可通过设置FZF_ALT_C_OPTS设置其他选项;

在tmux会话下,可以通过将FZF_TMUX设置为1来在拆分窗格中启动fzf,然后使用FZF_TMUX_HEIGHT更改窗格的高度(例如20%,50%等)。

如果在bash上使用vi模式,则需要在.bashrc中的source ~/.fzf.bash之前添加set -o vi,以使其正确设置vi模式的键绑定。

可以在Wiki页面上找到更多提示。

bash和zsh的模糊补全

文件和目录

如果光标前的单词以触发序列(默认为**)结尾,则可以触发文件和目录的模糊补全。

COMMAND [DIRECTORY/] [FUZZY_PATTERN] ** <TAB>

当前目录下的文件,可以使用TAB键选择多个项目

cat ** <TAB>

对父目录下的文件名补全

vim ../** <TAB>

父目录下匹配`fzf`的文件

vim ../fzf** <TAB>

用户主目录下的文件

cat ~/** <TAB>

当前目录下的目录(单选)

cd ** <TAB>

~/github下与`fzf`匹配的目录

cd ~/github/fzf** <TAB>

进程ID

PID的模糊补全提供给kill命令。在这种情况下,没有触发序列,只需在kill命令后按tab键即可。

可以使用<TAB>或<Shift-TAB>键选择多个进程

kill -9 <TAB>

主机名

对ssh和telnet命令,支持主机名的模糊补全。补全名称是从/etc/hosts和~/.ssh/config中获取的。

ssh ** <TAB>

telnet ** <TAB>

环境变量/别名

unset **<TAB>

export **<TAB>

unalias **<TAB>

默认配置项

触发关键字

比如使用~~作为触发关键字,不用默认的**,可通过设置:

export FZF_COMPLETION_TRIGGER='~~'

fzf命令的选项

export FZF_COMPLETION_OPTS='+c -x'

默认搜索工具

使用fd(github.com/sharkdp/fd)代替默认find命令列出路径

_fzf_compgen_path() {

fd --hidden --follow --exclude ".git" . "$1"

}

其中函数($1)的第一个参数开始便利的基础目录。

使用fd生成目录补全的列表:

_fzf_compgen_dir() {

fd --type d --hidden --follow --exclude ".git" . "$1"

}

增加命令支持

在bash上,仅对预定义的命令集启用了模糊补全,其详细里列表通过"complete | grep _fzf"查看。Fzf也支持对其进行扩展,方法是:

_fzf_setup_completion path|dir COMMANDS...

比如:

_fzf_setup_completion path ag git kubectl

_fzf_setup_completion dir tree

Vim插件

Fzf的Vim插件提供了两个核心功能fzf#run和fzf#wrap,其中:fzf命令基本文件选择器命令。

fzf#run([spec dict]):使用给定的规范在Vim中启动fzf,比如:

:call fzf#run({'source': 'ls'})

fzf#wrap([spec dict]) -> (dict) :采用fzf#run的规范,并返回其扩展版本以及用于处理全局首选项的其他选项(g:fzf_xxx)。

:echo fzf#wrap({'source': 'ls'})

通常在将规范传递给fzf#run之前将其包装在fzf#wrap

:call fzf#run(fzf#wrap({'source': 'ls'}))

:FZF [fzf_options string] [path string]:基本的模糊文件选择器,对那些不想编写VimScript来实现自定义命令的人的参考实现

用法

:FZF[!]

"在当前目录下查找文件

:FZF

在主目录下查找文件

:FZF ~

使用fzf命令行选项

:FZF --reverse --info=inline /tmp

与ctrlp.vim相似,使用Enter键,CTRL-T,CTRL-X或CTRL-V在当前窗口,新选项卡,水平分割或垂直分割中分别打开选定的文件。

注意,环境变量FZF_DEFAULT_COMMAND和FZF_DEFAULT_OPTS也起作用。

配置项

g:fzf_action:自定义的额外按键绑定,用于以不同方式打开所选文件

g:fzf_layout: 确定fzf窗口的大小和位置

g:fzf_colors: 自定义fzf颜色以匹配当前的配色方案

g:fzf_history_dir: 启用历史记录功能

fzf#run

fzf#run()函数是Vim集成的核心。它需要一个字典参数,一个规范,并相应地启动fzf进程。至少要指定接收器选项,以告诉它应该对所选条目执行的操作。

call fzf#run({'sink': 'e'})

上面没有指定源,所以这等效于在没有标准输入管道的情况下在命令行上启动fzf。fzf将使用find命令(或$ FZF_DEFAULT_COMMAND(如果已定义))列出当前目录下的文件。选择一个文件时候,它将使用接收器:e命令将其打开。如果要在新选项卡中打开它,则可以传递:tabedit命令作为接收器。

call fzf#run({'sink': 'tabedit'})

可以使用任何shell命令作为源,而不是使用默认的find命令。比如下面示例将列出git管理的文件。相当于shell命令行下运行git ls-files | fzf。

call fzf#run({'source': 'git ls-files', 'sink': 'e'})

可以将fzf选项指定为spec词典中的选项条目。

call fzf#run({'sink': 'tabedit', 'options': '--multi --reverse'})

不希望fzf窗口占据整个屏幕,还可以传递布局选项。

call fzf#run({'source': 'git ls-files', 'sink': 'e', 'left': '40%'})

call fzf#run({'source': 'git ls-files', 'sink': 'e', 'window': '30vnew'})

源不一定是外部shell命令,可以传递Vim数组作为源。下面的示例中,传递了颜色名称实现颜色方案选择器的源。

call fzf#run({'source': map(split(globpath(&rtp, 'colors/*.vim')),

\ 'fnamemodify(v:val, ":t:r")'),

\ 'sink': 'colo', 'left': '25%'})

fzf#wrap

前面说过:FZF命令的几个方面可以使用一组全局选项变量进行配置。使用不同的方式打开文件(g:fzf_action),窗口位置和大小(g:fzf_layout),调色板(g:fzf_colors)等不同的方式。那么,如何使我们的自定义fzf#run调用也能起作用呢?只需将其传递给fzf#run,然后用fzf#wrap修饰spec词典:

fzf#wrap([name string], [spec dict], [fullscreen bool]) -> (dict)

所有参数都是可选的。通常只需要传递一个规范字典。

name用于管理历史记录文件。如果未定义g:fzf_history_dir,则会被忽略。

fullscreeen 可设置为0或1(默认值:0)。

fzf#wrap接受一个规范,并返回它的扩展版本(也是字典),并带有用于解决全局首选项的其他选项。可以像这样检查它的返回值:

echo fzf#wrap({'source': 'ls'})

打包规范之后,就可将其传递给fzf#run。

call fzf#run(fzf#wrap({'source': 'ls'}))

现在,它支持CTRL-T,CTRL-V和CTRL-X键绑定,并根据g:fzf_layout设置打开fzf窗口。

为了使其易于使用,让我们定义LS命令使用。

command! LS call fzf#run(fzf#wrap({'source': 'ls'}))

然后就可以通:LS调用。

其他功能

性能问题

Fzf很快,而且会变得越来越快。在大多数情况下,性能都不是问题。但是有几个性能选项需要了解。

--ansi:告诉Fzf提取并解析输入中的ANSI颜色代码,这会使初始扫描变慢。因此,不建议将其添加到$FZF_DEFAULT_OPTS中。

--nth:该选项也会使fzf变慢,指定该选项后fzf必须对每行做标记。

--with-nth:该选项也会使fzf变慢,指定该选项后fzf必须每行标记并重新转载。

如果对想能有严苛要求,可以考虑使用--algo = v1(默认值为v2)使fzf使用更快的贪婪算法。但是,不能保证该算法找到最佳顺序的匹配,因此一般不建议使用。

执行外部程序

可以通过设置键绑定来启动外部进程,而无需离开fzf(execute,execute-silent)。

通过按F1键以较少的文件打开文件而不离开fzf,通过按CTRL-Y将行复制到剪贴板并中止fzf(需要pbcopy支持)

fzf --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'

预览窗口

设置--preview选项时,fzf会自动以当前行作为参数启动外部进程,并在拆分窗口中显示结果。

使用{}替换为焦点行的单引号字符串

fzf --preview 'cat {}'

由于预览窗口仅在该过程完成后才更新,因此该命令快速完成很重要。

使用head而不是cat,以便命令不会花费太长时间来完成

fzf --preview 'head -100 {}'

预览窗口支持ANSI颜色,因此可以使用语法突出显示文件内容的程序,比如和

bat、Highlight、CodeRay、Rouge等配合使用,比如下面的命令依次使用bat, highlight, coderay, rougify,然后回退到cat:

fzf --preview '[[ $(file --mime {}) =~ binary ]] &&

echo {} is a binary file ||

(bat --style=numbers --color=always {} ||

highlight -O ansi -l {} ||

coderay {} ||

rougify {} ||

cat {}) 2> /dev/null | head -500'

也可以使用--preview-window选项自定义预览窗口的大小和位置。例如,

fzf --height 40% --reverse --preview 'file {}' --preview-window down:1

fzf --height 40%--reverse --preview'file {}'--preview-window down:1

.gitignore

可以使用fd,ripgrep或silver搜索程序代替默认的find命令来遍历文件系统,搜索时候支持利用git忽略定义.gitignore文件排除文件和目录。

将fd的输出输入fzf

fd --type f | fzf

将fd设置为fzf的默认源

export FZF_DEFAULT_COMMAND='fd --type f'

设置后, fzf(不带管道)将使用fd代替find

也支持对CTRL-T命令使用:

export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"

如果要使该命令遵循符号链接,并且不希望其排除隐藏文件,可使用以下命令:

export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'

git ls-tree快速遍历

如果在大型git存储库中运行fzf,则使用git ls-tree可以提高遍历的速度。

export FZF_DEFAULT_COMMAND='

(git ls-tree -r --name-only HEAD ||

find . -path "*/\.*" -prune -o -type f -print -o -type l -print |

sed s/^..//) 2> /dev/null'

Fish Shell

Fish Shell 2.6.0之前的版本不允许在命令替换中从STDIN读取,所以简单的vim(fzf)将无法正常工作。 fish 2.5.0和更早版本需要使用使用read fish命令:

fzf | read -l result; and vim $result

对于多个结果:

fzf -m | while read -l r; set result $result $r; end; and vim $result

fish shell的glob系统系统和shell不同,所以**的补全功能将不起作用。但是,CTRL-T命令将使用命令行最后一个标记作为递归搜索的根文件夹。例如,在以下命令行的末尾按下CTRL-T

ls /var/

将列出/var/下的所有文件和文件夹。

使用自定义FZF_CTRL_T_COMMAND时,请使用未扩展的$dir变量来使用此功能。当最后不是有效目录时,$dir默认为.。 例:

set -g FZF_CTRL_T_COMMAND "command find -L \$dir -type f 2> /dev/null | sed '1d; s#^\./##'"

总结

Fzf是一款非常优秀、老少皆宜的开源系统工具,可以用来取代shell默认的搜索和补全行为。由于使用golang开发安装部署非常方便,性能也非常高。适合于开发者,运维和其他Linux用户,Github 2万多星就足以说明其多受欢迎了,非常值得大家使用。


评论
您未登录,请您先 登录
annidy
积分 429
排名 2
关注 0
收藏 0
项目 1
文章 16
问题 3
回答 3
关注 主页 消息
文章激励
  • 文章激励期间起每编文章活动奖励积分5分
  • 原创文章奖励积分10分
  • 每月完成30编文章额外奖励积分30分
  • 成为平台博主将成为合作客户,获得博客页面所有收益权
  • 参与并完成活动即送虚拟主机或mysql资源一份
  • 2021-11-19 ~ 2022-3-1
文章汇总
最新文章
2016 - 2021 © srczh.com 版权所有 增值电信经营许可:粤ICP备19068081号
深圳市中文远星科技有限公司