fzf - 命令行模糊搜索神器
fzf是一款使用 GO 语言编写的交互式的 Unix 命令行工具。
可以用来查找任何列表内容、文件、历史命令、 本机绑定的host、 进程、 Git 分支、进程
等。所有的命令行工具可以生成列表输出的都可以再通过管道 pipe 到 fzf 上进行搜索和查找
项目地址:https://github.com/junegunn/fzf
fzf 使用
fz f默认会从 STDIN 读入数据,然后将结果输出到 STDOUT
find * -type f | fzf
使用更快的fd
fd --type f | fzf
fzf默认环境变量
- 环境变量:如下表所示:
name | description | example |
---|---|---|
FZF_DEFAULT_COMMAND |
输入为 tty 时的默认命令 | export FZF_DEFAULT_COMMAND='fd --type f' |
FZF_DEFAULT_OPTS |
设置默认选项 | export FZF_DEFAULT_OPTS="--height 80% --layout=reverse --inline-info" |
FZF_CTRL_T_COMMAND |
按键映射<CTRL-T> 行为设置 |
|
FZF_CTRL_T_OPTS |
按键映射<CTRL-T> 选项设置 |
|
FZF_CTRL_R_OPTS |
按键映射<CTRL-R> 选项设置 |
|
FZF_ALT_C_COMMAND |
按键映射<CTRL-C> 行为设置 |
|
FZF_ALT_C_OPTS |
按键映射<CTRL-C> 选项设置 |
- 按键绑定:如下表所示:
fzf的安装脚本会为 bash,zsh 和 fish 终端设置以下按键绑定:
按键 | 描述 |
---|---|
CTRL-T |
命令行打印选中内容 |
CTRL-R |
命令行历史记录搜索,并打印输出 |
ALT-C |
模糊搜索目录,并进入(cd ) |
以zsh为例,.zshrc
source /usr/share/fzf/key-bindings.zsh
预览窗口
如果使用--preview选项, fzf会自动用外部程序打开现在条目的文件, {}会被fzf选中行内容代替
fzf --preview 'cat {}'
高亮输出:
- bat: https://github.com/sharkdp/bat
- highlight: http://www.andre-simon.de/dok...
- ccat:
- coderay: http://coderay.rubychan.de/
fzf --preview '[[ $(file --mime {}) =~ binary ]] && echo {} is a binary file || (bat --style=numbers --color=always{} || (ccat --color=always {} || highlight -O ansi -l {} || coderay {} || cat {}) 2> /dev/null | head -500'
}
export FZF_CTRL_T_OPTS="--preview '(highlight -O ansi -l {} 2> /dev/null || cat {} || tree -C {}) 2> /dev/null | head -200'"
实用脚本
以下脚本添加到fzf.zsh
文件,.zshrc
中引用
Changing directory
# fd - cd to selected directory
fd() {
local dir
dir=$(find ${1:-.} -path '*/\.*' -prune \
-o -type d -print 2> /dev/null | fzf +m) &&
cd "$dir"
}
# cda - including hidden directories
cda() {
local dir
dir=$(find ${1:-.} -type d 2> /dev/null | fzf +m) && cd "$dir"
}
# cdf - cd into the directory of the selected file
cdf() {
local file
local dir
file=$(fzf +m -q "$1") && dir=$(dirname "$file") && cd "$dir"
}
# cf - fuzzy cd from anywhere
# ex: cf word1 word2 ... (even part of a file name)
# zsh autoload function
cf() {
local file
file="$(locate -Ai -0 $@ | grep -z -vE '~$' | fzf --read0 -0 -1)"
if [[ -n $file ]]
then
if [[ -d $file ]]
then
cd -- $file
else
cd -- ${file:h}
fi
fi
}
Command history
# fh - repeat history
fh() {
eval $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g')
}
# fh - repeat history
fh() {
print -z $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g')
}
Replacing eval
with print -z
will push the arguments onto the editing buffer stack, allowing you to edit the command before running it. It also means the command you run will appear in your history rather than just fh
Processes
# fkill - kill process
fkill() {
local pid
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')
if [ "x$pid" != "x" ]
then
echo $pid | xargs kill -${1:-9}
fi
}
# fkill - kill processes - list only the ones you can kill. Modified the earlier script.
fkill() {
local pid
if [ "$UID" != "0" ]; then
pid=$(ps -f -u $UID | sed 1d | fzf -m | awk '{print $2}')
else
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')
fi
if [ "x$pid" != "x" ]
then
echo $pid | xargs kill -${1:-9}
fi
}
Interactive cd
Suggested by @mgild Like normal cd but opens an interactive navigation window when called with no arguments. For ls, use -FG instead of --color=always on osx.
function cdi() {
if [[ "$#" != 0 ]]; then
builtin cd "$@";
return
fi
while true; do
local lsd=$(echo ".." && ls -p | grep '/$' | sed 's;/$;;')
local dir="$(printf '%s\n' "${lsd[@]}" |
fzf --reverse --preview '
__cd_nxt="$(echo {})";
__cd_path="$(echo $(pwd)/${__cd_nxt} | sed "s;//;/;")";
echo $__cd_path;
echo;
ls -p --color=always "${__cd_path}";
')"
[[ ${#dir} != 0 ]] || return 0
builtin cd "$dir" &> /dev/null
done
}
fzf + zsh
配置文件.zshrc
# fzf
source /usr/share/fzf/key-bindings.zsh
source ~/.config/fzf/fzf.zsh
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git -E .cache'
export FZF_DEFAULT_OPTS='--height 80% --layout=reverse --preview-window down,30%,border-horizontal --preview "[[ $(file --mime {}) =~ binary ]] && echo {} is a binary file || (ccat --color=always {} || (bat --style=numbers --color=always{} || highlight -O ansi -l {} || cat {}) 2> /dev/null | head -500"'
#export FZF_CTRL_T_COMMAND=$FZF_DEFAULT_COMMAND
export FZF_CTRL_T_COMMAND='fd --type f -t d --hidden --follow --exclude .git -E .cache'
export FZF_ALT_C_COMMAND="fd --type d --hidden --follow"
fzf + ranger
ranger配置文件commands.py
- 方法一:
class fzf_select(Command):
"""
:fzf_select
Find a file using fzf.
With a prefix argument to select only directories.
See: https://github.com/junegunn/fzf
"""
def execute(self):
import subprocess
import os
from ranger.ext.get_executables import get_executables
if 'fzf' not in get_executables():
self.fm.notify('Could not find fzf in the PATH.', bad=True)
return
fd = None
if 'fdfind' in get_executables():
fd = 'fdfind'
elif 'fd' in get_executables():
fd = 'fd'
if fd is not None:
hidden = ('--hidden' if self.fm.settings.show_hidden else '')
exclude = "--no-ignore-vcs --exclude '.git' --exclude '*.py[co]' --exclude '__pycache__'"
only_directories = ('--type directory' if self.quantifier else '')
fzf_default_command = '{} --follow {} {} {} --color=always'.format(
fd, hidden, exclude, only_directories
)
else:
hidden = ('-false' if self.fm.settings.show_hidden else r"-path '*/\.*' -prune")
exclude = r"\( -name '\.git' -o -iname '\.*py[co]' -o -fstype 'dev' -o -fstype 'proc' \) -prune"
only_directories = ('-type d' if self.quantifier else '')
fzf_default_command = 'find -L . -mindepth 1 {} -o {} -o {} -print | cut -b3-'.format(
hidden, exclude, only_directories
)
env = os.environ.copy()
env['FZF_DEFAULT_COMMAND'] = fzf_default_command
env['FZF_DEFAULT_OPTS'] = '--height=80% --layout=reverse --ansi --preview-window down,30% --preview="{}"'.format('''
(
batcat --color=always {} ||
bat --color=always {} ||
cat {} ||
tree -ahpCL 3 -I '.git' -I '*.py[co]' -I '__pycache__' {}
) 2>/dev/null | head -n 100
''')
fzf = self.fm.execute_command('fzf --no-multi', env=env,
universal_newlines=True, stdout=subprocess.PIPE)
stdout, _ = fzf.communicate()
if fzf.returncode == 0:
selected = os.path.abspath(stdout.strip())
if os.path.isdir(selected):
self.fm.cd(selected)
else:
self.fm.select_file(selected)
- 方法二:
# fzf
lass fzf_select(Command):
"""
:fzf_select
Find a file using fzf.
With a prefix argument select only directories.
See: https://github.com/junegunn/fzf
"""
def execute(self):
import subprocess
import os.path
if self.quantifier:
# match only directories
command="find -L . \( -path '*/\.*' -o -fstype 'dev' -o -fstype 'proc' \) -prune \
-o -type d -print 2> /dev/null | sed 1d | cut -b3- | fzf +m"
else:
# match files and directories
command="find -L . \( -path '*/\.*' -o -fstype 'dev' -o -fstype 'proc' \) -prune \
-o -print 2> /dev/null | sed 1d | cut -b3- | fzf +m"
fzf = self.fm.execute_command(command, universal_newlines=True, stdout=subprocess.PIPE)
stdout, stderr = fzf.communicate()
if fzf.returncode == 0:
fzf_file = os.path.abspath(stdout.rstrip('\n'))
if os.path.isdir(fzf_file):
self.fm.cd(fzf_file)
else:
self.fm.select_file(fzf_file)
ranger配置文件rc.conf
设置快捷键
# fzf
map <C-f> fzf_select
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)