Understand and then Extend Fuzzy Finders
Prerequisite: basic bash scripting knowledge
Fuzzy finders are a class of programs that do something very basic. Given a list of text, a fuzzy finder wait for user inputs, and, as the user types, it will filter the list items depending on how well the input pattern matches. The result of the program is simply the selected item.
They are called “fuzzy” because they can compensate for 1 or 2 character errors by being approximate in the pattern matching, like most web search engines.
The approach of fuzzy finders is showcased below with the popular
fzf
shell program.
However, keep in mind that fuzzy finders programs exist outside the shell, e.g.
dmenu
for the desktop environment or
telescope
inside neovim
.
The same principles hold.
Showcasing fzf
, bare bones
fzf
gets the list items from the standard input and provide the
selected item in the standard output.
A short script to select a color would look like this:
echo -e "DarkGreen\n\
Red\n\
Green\n\
Blue\n\
White\n\
Black\n\
Yellow\n\
Magenta" | fzf

In order to select the entry “Green”, the letters “gr” are typed by the user. This causes the list items to be filtered according to the “gr” pattern. Pressing enter validates the best match among those filtered items and delivers it to the standard output.
It is worth noting that it is still our job both to come up with the list
items for fzf
, and to exploit the selected item once it is available in the
standard output.
Hence, to become a valuable in your workflow, you have to combine fuzzy finder with some bash scripting.
Some Use Cases
To contemplate the possibilities offered by fuzzy finders, I propose a few one-liner scripts. I generally use aliases to transform them into a custom command to avoid all the typing.
-
Pick a config file to open with the editor. Assume that the path list of the config files path is held in the
PATH_CONFIGS
shell variable.$EDITOR "$(echo $PATH_CONFIGS | fzf)"
-
Navigate to any git repository in your home folder. I use the fact that a git repository has a
.git
hidden directory.cd "$(fd '^.git$' -H $HOME | xargs -I _ dirname _ | fzf)"
-
Open a PDF somewhere in your system using its filename. You might even combine this with
pdf2info
to open a PDF according to some metadata (author, year, conference …).xdg-open $(fd '*.pdf$' | fzf)
-
Fire up a Python environment managed by
conda
. The list ofconda
environments is accessible through the commandconda env list
.# conda environments: # base * /home/joel/miniconda3 cling /home/joel/miniconda3/envs/cling cv /home/joel/miniconda3/envs/cv ros_env /home/joel/miniconda3/envs/ros_env sparse_matrices /home/joel/miniconda3/envs/sparse_matrices
This output from
conda env list
requires some cleaning before going intofzf
.conda activate $(conda env list | sed '/^#/d' | sed '/^$/d' | cut -d' ' -f1 | fzf)
In this case, the
sed
commands deletes all comment lines (that start with#
) and empty lines, thecut
command picks the first space-separated field.
Advanced Usage
You can add flags to fzf
command to add previews, colors and much more to improve interactivity.
One such elaborate example (found here):
#!/usr/bin/env bash
# 1. Search for text in files using Ripgrep
# 2. Interactively narrow down the list using fzf
# 3. Open the file in $EDITOR
IFS=: read -ra selected < <(
rg --color=always --line-number --no-heading --smart-case "${*:-}" |
fzf --ansi \
--color "hl:-1:underline,hl+:-1:underline:reverse" \
--delimiter : \
--preview 'bat --color=always {1} --highlight-line {2}' \
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
)
[ -n "${selected[0]}" ] && $EDITOR "${selected[0]}" "+${selected[1]}"
Performance Considerations
Even on large lists, containing thousands of items, the filtering algorithm is
really fast. The bottleneck generally arises when the list items are assembled,
before going into fzf
.
This typically happens if we require something to be searched across the whole
filesystem, e.g. searching some text inside a file of which you don’t know or the name or the location.
We can mitigate that hindrance by ignoring some paths voluntarily. In the navigation-to-git-repository
script above, we can exclude the .local
, .cache
and .cargo
directories to
speed up the process considerably.
cd "$(fd '^.git$' -H $HOME -E ".local" -E ".cache" -E ".cargo" | xargs -I _ dirname _ | fzf)"
Another technique consists in caching our list items in a file or in an environment variable, see the bullet point ‘config’ example.
Conclusion
As we have seen, fuzzy finders are easy to extend by virtue of their simplicity. They follow the so-called Unix philosophy: “do one thing and do it well”, and let the user figure out the rest.