DEV Community

Steve Stine
Steve Stine

Posted on

Fuzzy Find Everything

Imagine searching, editing, and executing files in your terminal so quickly that the friction disappears.

You type a loose, typo-filled query like "contrler bugfix" — and instantly see "controller_fix_2025.py" rise to the top of the list, even in a monorepo with thousands of files. No exact spelling required. No tab-mashing through long paths. Just start typing what you half-remember, watch the results narrow in real time, and hit Enter.

fzf turns any list piped into it (files, command history, git branches, running processes, you name it) into a fast, interactive fuzzy finder. It handles massive directories in milliseconds and makes navigation feel almost thought-to-action.

Traditional tools demand precision:

  • ls | grep needs correct spelling and order
  • Tab completion struggles with typos or forgotten segments
  • find requires full paths or complex flags

fzf forgives all of that. Type loosely, in any order, with gaps or abbreviations — it ranks intelligently and shows context so you can decide confidently.

What is fuzzy search

Fuzzy search finds approximate matches instead of demanding exact strings.
Type "contrler bugfix" and it finds "controller_fix_2025.py" even with typos, skipped letters, out-of-order words, or abbreviations.
Traditional tools like ls | grep, tab-completion, or find require precise spelling and full paths – frustrating when you half-remember a filename or are working in massive projects.
fzf is the interactive command-line fuzzy finder that turns any list (files, history, git branches, processes…) into a fast, beautiful, searchable interface.
Pipe anything into it via stdin, start typing loosely, and hit Enter – it handles huge directories in milliseconds.
Bonus: It's not just files. fzf supports Ctrl+R history search, directory jumping, killing processes, and more.
Once set up, it becomes muscle memory.
In this guide, we'll install fzf, enable its standard functions, then go deep into previews, custom scripts, and keybinds that make your terminal feel FAST.

How to get it

Installing fzf with your package manager is the most straight forward method.

For linux:

# Debian and Ubuntu
sudo apt install fzf

# Fedora
sudo dnf install fzf

# Arch
sudo pacman -S fzf

# Gentoo
emerge --ask app-shells/fzf

# OpenSUSE
sudo zypper i fzf
Enter fullscreen mode Exit fullscreen mode

There are also package managers for Windows.
Chocolatey, if you have admin access:

choco install fzf -y
Enter fullscreen mode Exit fullscreen mode

or Scoop if you don't:

scoop install fzf
Enter fullscreen mode Exit fullscreen mode

And macOS can install with Homebrew

brew install fzf
Enter fullscreen mode Exit fullscreen mode

The most up to date releases for all operating systems are also available here

Standard functions

The newer versions of fzf come packaged with standard keybinds and search scripts.
You can enable them on linux with:

echo 'eval "$(fzf --bash)"' >> ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

Reload your shell (source ~/.bashrc) or restart terminal.
This unlocks:

Ctrl+T → fuzzy file search in current dir (inserts path)
Ctrl+R → fuzzy command history search
Alt+C → fuzzy cd to subdirectory

Stop here and your searching is already superior than stock.
Keep reading for previews, custom scripts, and global keybinds.

Power User: keybinds and shell integration

If you're not afraid to get your hands a bit dirty, fzf can become very powerful.
This section is about minimizing the time it takes to get where the work is.

File previews

Using the --preview flag, you can see what you're about to open, edit, or execute.

Here's a simple example using the preview flag to try out:

fzf --preview 'cat {}'
Enter fullscreen mode Exit fullscreen mode

It will try to show you what's in the file while you're searching.
This is pretty good, but we can do better:

fzf --preview 'bat --color=always --style=numbers {}'
Enter fullscreen mode Exit fullscreen mode

This one shows the same text, but with syntax highlighting and line numbers.
It uses bat or batcat to do the highlighting and numbers.
To install bat:

sudo apt install bat
Enter fullscreen mode Exit fullscreen mode

This is the exact command that's executing in the above screenshot:

fd --type f --hidden --exclude .git . / 2>/dev/null | \
fzf --height 75% --layout=reverse --border --preview \
'if file --mime-type {} | rg -q text; then bat --color=always --style=numbers {}; else cat {}; fi'
Enter fullscreen mode Exit fullscreen mode

That's one long command!
This is what's going on:
First it calls the find command, fd, to search for files.
The second line takes the results and gives it to fzf.
And we've already seen that the preview flag and bat give highlighted outputs.

I'll be relying on this command for the rest of the article.
Getting this to work as pictured above, you'll need to install a few more programs:

sudo apt install bat fd-find ripgrep
Enter fullscreen mode Exit fullscreen mode

fd or fd-find is a fast search program.
And rg or ripgrep is a fast regular expression search tool.

Find and execute scripts

We're going to use the above command and execute scripts with a function in .bashrc.

fzf_execute() 
{                                                              
    script=$(fd --type f --hidden --exclude .git --exclude /proc --exclude / sys . / 2>/tmp/fzf_fd_errors.log | fzf --height 75% --layout=reverse --border --preview 'if file --mime-type {} | rg -q text; then bat --color=always --style=numbers {}; else cat {}; fi')                                    
    if [[ -n "$script" ]]; then                                             
        echo "$script" > /tmp/fzf_selected_script                           
        $HOME/Configs/fzf/fzf_execute.sh                                     
    fi                                                                      
}  
Enter fullscreen mode Exit fullscreen mode

Now, typing fzf_execute in your terminal will start the search.
The if statement writes the path of the selected file to a temporary location and calls a script.

#!/bin/bash
#########################
# Reads a path to file  #
# from tmp and tries to # 
# execute it; .sh .py   #
#                       #
# tmp is fed by fzf f() #
# out in .bashrc        #
#########################

if [[ ! -f /tmp/fzf_selected_script ]]; then
  exit 1
fi

selected_script=$(cat /tmp/fzf_selected_script)

# Convert relative path to absolute path
selected_script=$(realpath "$selected_script" 2>/dev/null)

if [[ ! -f "$selected_script" ]]; then
  exit 1
fi

rm -f /tmp/fzf_selected_script

# Get the file extension (lowercase)
extension=$(echo "${selected_script##*.}" | tr '[:upper:]' '[:lower:]')

# Function to open/execute the file based on its extension
open_file() {
    case "$extension" in
        sh)
            # Execute bash scripts
            if [[ -x "$selected_script" ]]; then
                "$selected_script"
            else
                bash "$selected_script"
            fi
            ;;
        py)
            # Run Python scripts
            python3 "$selected_script"
            ;;
        xlsx|ods|csv)
            # Open spreadsheets with LibreOffice Calc
            libreoffice --calc "$selected_script" &
            ;;
        docx|odt)
            # Open documents with LibreOffice Writer
            libreoffice --writer "$selected_script" &
            ;;
        pdf)
            # Open PDFs with default PDF viewer
            xdg-open "$selected_script" &
            ;;
        jpg|jpeg|png|gif)
            # Open images with default image viewer
            gimp "$selected_script" &
            ;;
        mp4|mov|avi|mkv|mp3|flac)
            # Open videos with default video player
            vlc "$selected_script" &
            ;;
        txt|md|log)
            # Open text files with default text editor
            vim "$selected_script" &
            ;;
        *)
            # Fallback: Try to open with default application
            if command -v xdg-open >/dev/null 2>&1; then
                xdg-open "$selected_script" &
            else
                echo "Error: No handler found for file extension '$extension'"
                exit 1
            fi
            ;;
    esac
}

# Check if the file is executable and run directly if it is
if [[ -x "$selected_script" && "$extension" != "sh" ]]; then
    "$selected_script"
else
    open_file
fi
Enter fullscreen mode Exit fullscreen mode

"fzf_script.sh" will take the file path an determine what filetype it is and open it.
So if it's a media file, it'll open it with vlc; text file, vim; and so on.
For python and bash scripts (or any other you choose), it will try execute them.

Now, I can type "fzf_script" in my terminal, search for a docx file, and launch libreoffice to open it.
Changing fzf_script.sh will be necessary to use your preferred programs like openoffice or kate.

Find and edit files

If you want to edit files in your favorite text editor, add another .bashrc function.

fzf_edit() 
{                                                        
    file=$(fd --type f --hidden --exclude .git . / 2>/dev/null | fzf --height 75% --layout=reverse --border --preview 'if file --mime-type {} | rg -q text; then bat --color=always --style=numbers {}; else cat {}; fi')        

    if [[ -n "$file" ]]; then                                                 
        echo "$file" > /tmp/fzf_selected_file                                   
        ~/Configs/fzf/fzf_vim.sh                                           
    fi                                                                        
} 
Enter fullscreen mode Exit fullscreen mode

Notice our find command is almost the same as before, just excluding less files.
We also call a different script in our if statement.

#!/bin/bash                                                                 
#########################                                                   
# Reads file path from  #                                                   
# tmp and tries to open #
# file in vim           #
#                       #
# tmp fed by fzf f() in #
# .bashrc               #
#########################

if [[ ! -f /tmp/fzf_selected_file ]]; then
    echo "No file selected by fzf"
    exit 1
fi

selected_file=$(cat /tmp/fzf_selected_file)

vim -u ~/Configs/.vimrc "${selected_file}"

rm -f /tmp/fzf_selected_file

Enter fullscreen mode Exit fullscreen mode

It will try to open the selected file in a text editor only.

Adding keybinds

fzf is most useful when the functions and scripts above are triggered from simple key binds.

In your .bashrc add these at the bottom:

bind -r '\C-x'                                                              
bind -x '"\C-x": fzf_execute'                                                

bind -r '\C-f' # Remove current binding                                     
bind -x '"\C-f": fzf_edit' # start file search function 
Enter fullscreen mode Exit fullscreen mode

"bind -r" will remove all functionality currently associated with that key combination.
"bind -x" will then add the functionality you want.

The first line removes all functionality associated with ctrl-x.
The second line associates the ctrl-x key combination with the bash function fzf_script.

Now, while at a terminal, pressing ctrl-x will start your search to open or execute any file.
Pressing ctrl-f will now start your search to edit any file.

From here, you should be able to add your own customized keybinds and scripts.

Top comments (0)