Using FZF to Improve Productivity

By Akash Khan

Consider the following problem.

Given an array of strings find all strings that match a given pattern. For example consider the input array to be ['apple', 'ball', 'cat', 'doll'] and the pattern to be al.
Looking at the array we can see that ball is the only string that matches the pattern exactly and it's not very difficult to implement an algorithm to detect this. However a much more interesting version of the problem is when we remove the restriction that the characters in the pattern should appear together. In the above example it would mean that our algorithm would need to output ['apple' , 'ball'].
This is known as fuzzy matching. It is part of a larger group of problems known as Approximate String Matching

FZF is a commandline fuzzy finder which solves the above problem . It reads the list from STDIN and writes the result to STDOUT. What makes it special though is that it is extremely fast and extensible. Combined with Unix pipelines we can create some very useful functions.

Setting up and basic usage

Check out the github page for installation instructions. It’s available for every major platform and can be setup very easily. Once done you should have the fzf executable added.
Using fzf is very easy. All the commands I will be talking about follow the same structure .

  1. First you have the input command which generates the input list .
  2. Second you pass this list to the fzf executable using | operator and fzf will generate the UI for pattern matching.
  3. Once the user inputs the pattern fzf will pass the results to STDOUT and we can use the | operator again to use these results.

In general

command 1 {options} | command 2 ... | fzf {options} | command n | command n+1 ...

For example

Advanced Usage

Since fzf is built to be extensible, it works very well with other unix commands and by composing different commands we can create powerful interfaces. I have listed a few which I’ve been using below:

  • Navigating directories ( Replacing cd )
sh function fd() { 
local dir dir=$(find ${1:-.} -path ‘*/\.*’ -prune \ -o -type d -print 2> /dev/null | fzf +m) && cd “$dir”
}
function fdr() {
local declare dirs=()
## Recursively fetch parent directories
get_parent_dirs() {
if [[ -d "${1}" ]]; then dirs+=("$1"); else return; fi
if [[ "${1}" == '/' ]]; then
for _dir in "${dirs[@]}"; do echo $_dir; done
else
get_parent_dirs $(dirname "$1")
fi
}
local DIR=$(get_parent_dirs $(realpath "$PWD") | fzf +m)
cd "$DIR"
}
  • Killing processes
fkill() {
local pid
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')
if [ "x$pid" != "x" ]
then
echo $pid | xargs kill -9
fi
}
  • Searching git commits
function gitlog() {
## git log -> fzf -> extract commit SHA -> git show
git log --graph --color=always \
--format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
fzf --ansi --no-sort --reverse --tiebreak=index --toggle-sort=\` \
--bind "ctrl-m:execute:
echo '{}' | grep -o '[a-f0-9]\{7\}' | head -1 |
xargs -I % sh -c 'git show --color=always % | less -R'"
}

If you are a Vim/Neovim user like me, you would be glad to know that FZF also comes with a built-in integration for Vim which can be used to navigate through your code base!

Conclusion

The above scripts are just a small subset of the things we can do with fzf. By composing different commands, we can create very powerful interfaces which can help save time. The FZF Wiki page contains some very good documentation and examples for getting started.

Akatsuki Taiwan Technology

Engineer Blog of Akatsuki Taiwan

Akatsuki Taiwan Technology

Engineer Blog of Akatsuki Taiwan

Akatsuki Taiwan Technology

Engineer Blog of Akatsuki Taiwan