Blog Post Publish Date: 2024/04/28
fzf: Life is Too Short for Pipe Grep#
This blog post outlines the advantages of the fzf (Fuzzy Finder CLI) and explains how to configure its Zsh widgets.
Searching in the Terminal - Tedious Task#
Searching for items in the terminal is a trivial activity, but can be a boring and tedious task. I will list three cases to exemplify it: searching command history; files and directories; and command output.
Usually, users press the arrow up/down to recall last commands executed. The most used shells implemented an interactive search tool called by CTRL
+ R
shortcut. In Zsh, it is implemented as reverse-i-search, which works well, but you need to press the shortcut again to see the next results. This behavior can be a problem if you need to recall commands executed multiple times with different arguments.
When it is necessary to find some file or directory, the most common method adopted is to use $ find
. It works well when you know exactly the item that you need to find, but not so good when you only know some partials of the path.
Lastly, I can mention searching elements in command outputs. The most adopted method for this case is to use matching expressions within a command output using $ command | grep
. When the same problem of finding files and directories previously described is true for this. Depending on the case, it is necessary to execute grep multiple times until you find the elements that you need.
This tedious task prompted me to research better alternatives for interactive searching.
Fuzzy Finders - The Solution#
After a few days of research, I found an amazing project that solves my problems: fzf — command-line fuzzy finder. It is a cross-platform Fuzzy Finder command-line written in Go. But, what is Fuzzy Finder?
Fuzzy Finder is a search tool category for providing a quickly and flexibly way to find files, directories, or other elements, even when they don’t remember the precise names. It employs fuzzy matching to find results based on partial words, erratic characters, or typographical errors.
fzf filters the list of items as you type. This makes your searching much more efficient, avoiding $ command | grep
execution. It can receive output of the other commands for interative searching, for instance you can execute $ kgp -A | fzf
to find pods in a Kubernetes cluster. In addition, it has some predefined shells widgets to search files, directories, and search history commands.
The next section will explain how to configure these widgets in Zsh.
There are widgets available for Fish, Bash, Zsh. You can check the available implementations in github.com/junegunn/fzf/shell
How to Configure fzf Widgets in Zsh#
The first step is to install fzf. There are some distinct ways to install it described in fzf — installation section. Depending on the package manager on your workstation, the version available can be older. Thus, I will download and install the latest version available in GitHub Releases section.
setopt INTERACTIVE_COMMENTS
# download the latest version (in a moment of the blog publish date, the latest version is 0.50.0)
curl -L https://github.com/junegunn/fzf/releases/latest/download/fzf-0.50.0-linux_amd64.tar.gz > fzf-0.50.0-linux_amd64.tar.gz
# uncompress the donwloaded file to access the fzf binary
tar -xzvf fzf-0.50.0-linux_amd64.tar.gz
# check fzf binary execution
./fzf --help
# move the binary to a folder present in your path
mv fzf /usr/local/bin/
The fzf use the command $ find
behind the scenes as engine to search directories and files. You can change it. In this example, I will install and configure the fd-find, a fast and user-friendly alternative to $ find
.
# In Linux workstation with dnf package manager
dnf install fd-find
# In MacOs workstation with homebrew package manager
brew install fd
For file content preview, I will install and configure bat, a $ cat
clone with syntax highlighting.
# In Linux workstation with dnf package manager
dnf install bat
# In MacOs workstation with homebrew package manager
brew install bat
For directory and sub directories preview, I will install and configure tree, a utility which recursively displays the contents of directories in a tree-like format.
# In Linux workstation with dnf package manager
dnf install tree
# In MacOs workstation with homebrew package manager
brew install tree
Now, it is necessary load the Shell widgets. For this, you can get the widget setup source-code given the shell name as argument (--zsh
, --fish
, --bash
). In this case, I will setup the widgets for Zsh.
# Set up fzf key bindings and fuzzy completion (only available in 0.48.0 or later)
eval "$(fzf --zsh)"
Run the following command to check the keybindings are correctly loaded.
bindkey -a | grep fzf
# output expected:
#
# "^R" fzf-history-widget # CTRL + R: reverse history search
# "^T" fzf-file-widget # CTRL + T: search files
# "^[c" fzf-cd-widget # ALT + C: search directories
You can customize the widgets fzf parameters through environment variables described in fzf — environment variables. Each widget has its own environments variables you can customize based on your needs. Take a look at following code block for an example of the how to parametrize fzf widgets.
# fzf parameters used in all widgets - configure layout and wrapped the preview results (useful in large command rendering)
export FZF_DEFAULT_OPTS="--height 100% --layout reverse --preview-window=wrap"
# CTRL + R: put the selected history command in the preview window - "{}" will be replaced by item selected in fzf execution runtime
export FZF_CTRL_R_OPTS="--preview 'echo {}'"
# ALT + C: set "fd-find" as directory search engine instead of "find" and exclude "venv|virtualenv|.git" of the results during searching
export FZF_ALT_C_COMMAND="fd --type directory --exclude venv --exclude virtualenv --exclude .git"
# ALT + C: put the tree command output based on item selected
export FZF_ALT_C_OPTS="--preview 'tree -C {}'"
# CTRL + T: set "fd-find" as search engine instead of "find" and exclude "venv|virtualenv|.git" for the results
export FZF_CTRL_T_COMMAND="fd --exclude venv --exclude virtualenv --exclude .git"
# CTRL + T: put the file content if item select is a file, or put tree command output if item selected is directory
export FZF_CTRL_T_OPTS="--preview '[ -d {} ] && tree -C {} || bat --color=always --style=numbers {}'"
The next section will present widgets executions preview.
You can check my
~/.zshrc
file content in the following link. It contains my personal fzf parametrization: c-neto/ansible-configure-fedora
Results#
fzf-history-widget executed by
CTRL
+R
.
fzf-cd-widget executed by
ALT
+C
.
fzf-file-widget executed by
CTRL
+T
.
Searching pods in Kubernetes Cluster with
$ kgp -A | fzf
execution.
Links#
$ bat
reference: sharkdp/bat$ fd
reference: sharkdp/fd$ fzf
reference: junegunn/fzf$ tree
reference: https://www.cyberciti.biz/faq/linux-show-directory-structure-command-line/$ zsh
reference: https://www.zsh.org/My custom fzf configuration in
~/.zshrc
: c-neto/ansible-configure-fedoraextra:
$ skim
, a fzf implemented in rust: lotabout/skim