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.

fzf

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.

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.