Using FZF to boost command line productivity
I discovered fzf a few years ago and it has greatly improved my command line productivity. In this post, I will explain how it works and introduce my 3 everyday usage cases.
The author of fzf, Junegunn Choi, also created vim-plug, fzf.vim, and other useful vim plugins.
basic concepts
Fzf is a command-line fuzzy finder.
If you know the unix pick
command, fzf
is simply pick
with fuzzy
filtering as you type keywords. Please feel free to skip to the usage cases.
For those who don’t know pick
, fzf
lets you interactively
select item(s) from a list of choices.
If you run fzf
in shell directly, the default behavior is to show all files
in current directory recursively as choices, i.e., find * -type f
.
See the screenshot of my gita repo.
You can use arrow keys to hover over different choices.
Typing any words will fuzzily limit the choices, and hitting the Enter
key makes the choice.
The default behavior is controlled by FZF_DEFAULT_COMMAND
. For example
you can use fd
instead of find
by adding
the following line in the .bashrc
export FZF_DEFAULT_COMMAND='fd --type f'
You can pass choices to fzf
too, for example
ps -ef | fzf
ls *.txt | fzf
qstat -u $USER | fzf
cat data.csv | fzf
I use a command line note taking program called notes,
and I have this line in my .bashrc
alias vn='n ls |fzf | n o'
This vn
alias opens a note via fzf
selection.
Here n
is my alias to notes
, n ls
lists the documents and n o
opens
the one picked by fzf
.
navigate directories with z
I use z to change directories. It maintains a list
of directories to cd
into, based on frequency and recentness.
With fzf
integration, you can see the choices explicitly.
z() {
[ $# -gt 0 ] && _z "$*" && return
cd "$(_z -l 2>&1 | fzf --height 40% --nth 2.. --reverse --inline-info +s --tac --query "${*##-* }" | sed 's/^[0-9,.]* *//')"
}
kill jobs
In my work, I use qstat
to view submitted jobs to HPC
clusters and qdel
to delete unwanted jobs.
The same idea in this section works for deleting local jobs with ps
and kill
too.
However that integration is shipped with fzf
: try kill <tab>
.
By default, fzf
only makes one choice. To allow multiple choices with tab
key, add this line in .bashrc
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border --multi'
My alias to kill jobs is
alias qd='qdel `q | tail -n +3| fzf | ff 1`'
Here ff
is a custom script to extract a column:
awk "{ print \$$1 }"
which I stole from The Unix Programming Environment.
It is more versatile than hard coding a field in the awk
command.
And q
is my tailored qstat
command
alias q='qstat -u $USER| tee >(tail -n +3 |wc -l)'
The tail -n +3
command gets rid of the header of the qstat
output.
edit source files in a git repo
With the help of fzf
and fzf.vim, I
always stay at the root of git repos to edit files.
While one can use vim `fzf`
, the following function is more powerful.
fe() {
IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0))
[[ -n "$files" ]] && ${EDITOR:-vim} -O "${files[@]}" -p
}
Notice that --multi
allows multiple selections by tab
key.
The -O
option for vim
opens multiple files in vertical splits
(-p
may also be a good choice).
When already in vim
, you can use the following shortcuts to open files
let mapleader = ","
nmap <leader>f :GFiles!<CR>
nmap <leader>o :Files!<CR>
These two vim
colon commands are defined by fzf.vim
and there are other
useful ones such as :Rg
, :BLines
, :BCommits
, etc.