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 | grepneeds correct spelling and order - Tab completion struggles with typos or forgotten segments
-
findrequires 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
There are also package managers for Windows.
Chocolatey, if you have admin access:
choco install fzf -y
or Scoop if you don't:
scoop install fzf
And macOS can install with Homebrew
brew install fzf
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
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 {}'
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 {}'
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
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'
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
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
}
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
"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
}
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
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
"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)