How to Use fzf, the Fuzzy Finder
Install and configure fzf to fuzzy-search files, shell history, processes, and git branches — with shell integration for Bash, Zsh, and Fish.
Before you start
- ▸A working Bash, Zsh, or Fish shell with a writable RC file
- ▸sudo or root access to install packages
- ▸Optional but recommended: fd and bat installed for enhanced file search and previews
- ▸Basic familiarity with editing shell configuration files
fzf is an interactive fuzzy finder that turns almost any list of text into a searchable, filterable menu. Once it's wired into your shell, you'll use it dozens of times a day — to jump to files, replay commands, kill processes, and navigate git history — all without leaving the terminal.
Installation
Debian / Ubuntu
sudo apt install fzf
The packaged version on older LTS releases may lag behind upstream. For the latest version, use the Git method below or grab a release binary from the fzf releases page.
Fedora / RHEL 9+ / Rocky 9+
sudo dnf install fzf
Arch Linux
sudo pacman -S fzf
From Git (any distro, always current)
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
The installer asks whether to enable key bindings and shell completion — say yes to both. It patches your ~/.bashrc or ~/.zshrc automatically.
Shell Integration
Shell integration provides three essential key bindings and tab-completion triggers. If you installed from your package manager, you must source the integration files manually. Add the relevant block to your shell's RC file.
Bash
# Add to ~/.bashrc
source /usr/share/doc/fzf/examples/key-bindings.bash
source /usr/share/bash-completion/completions/fzf
Zsh
# Add to ~/.zshrc
source /usr/share/doc/fzf/examples/key-bindings.zsh
source /usr/share/doc/fzf/examples/completion.zsh
Fish
# Fish uses its own integration package
pacman -S fzf # or apt/dnf
# Then add to ~/.config/fish/config.fish:
fzf --fish | source
File paths for the integration scripts vary slightly between distros. On Fedora they live under /usr/share/fzf/. Run rpm -ql fzf or dpkg -L fzf if you can't find them.
After editing your RC file, reload it:
source ~/.bashrc # or ~/.zshrc
The Three Core Key Bindings
Once integration is active, three bindings cover the majority of daily use.
- Ctrl-T — paste a selected file or directory path onto the command line.
- Ctrl-R — search shell history interactively; press Enter to execute the selected command.
- Alt-C — fuzzy-search directories and
cdinto the chosen one immediately.
Searching Files
Running fzf alone opens a full-screen finder over the output of find starting from the current directory. Start typing to narrow results; the match is fuzzy, so bshrc will match .bashrc.
fzf
Open the selected file in your editor directly:
nvim "$(fzf)"
Use fd instead of the default find for faster, git-aware searches. Set it as the default source via the environment variable:
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
Add a live preview of file contents with bat (a cat replacement with syntax highlighting):
export FZF_DEFAULT_OPTS="--height 50% --layout=reverse --preview 'bat --color=always --line-range :100 {}'"
Searching Shell History
Ctrl-R replaces the default reverse-history search with an fzf interface. Every command you've run appears; type fragments from anywhere in the command string to filter.
To search history and print the result (useful in scripts):
history | fzf --tac --no-sort | sed 's/^ *[0-9]* *//'
--tacreverses the order so recent entries appear first.--no-sortpreserves that recency order instead of sorting by match score.
Finding and Killing Processes
Pipe ps output into fzf to select processes interactively, then extract the PID for kill:
kill -9 $(ps aux | fzf --header-lines=1 | awk '{print $2}')
--header-lines=1 freezes the ps column header so it's visible but not selectable. This is a sharp tool — confirm the right process before pressing Enter.
For a reusable version, add a shell function to your RC file:
fkill() {
local pid
pid=$(ps aux | fzf --header-lines=1 --multi | awk '{print $2}')
if [ -n "$pid" ]; then
echo "$pid" | xargs kill -${1:-9}
fi
}
--multi lets you select multiple processes with Tab before confirming. Call it as fkill or fkill 15 to send SIGTERM instead.
Git Integration
fzf pairs naturally with git's plumbing commands to build fast, visual workflows.
Checkout branches interactively
git checkout $(git branch --all | fzf | tr -d ' ')
Browse and show commits
git log --oneline | fzf --preview 'git show --stat --color=always {1}'
The {1} placeholder passes the first field (the commit hash) to git show. The preview pane updates as you move the cursor.
Stage files interactively
git diff --name-only | fzf --multi --preview 'git diff --color=always {}' | xargs git add
For a richer git+fzf experience, look at forgit, a plugin that wraps common git operations with fzf interfaces including interactive rebase, stash management, and blame browsing.
Useful fzf Options
| Option | Effect |
|---|---|
--multi | Select multiple items with Tab; outputs one per line |
--height 40% | Open inline rather than full-screen |
--layout=reverse | Input at top, list below (feels more natural) |
--preview 'cmd {}' | Run a command on the highlighted item; show output in a side pane |
--bind 'ctrl-/:toggle-preview' | Toggle preview pane with a key |
--query 'initial' | Pre-fill the search box |
--exact | Switch to exact (non-fuzzy) matching |
Verification
Confirm fzf is installed and integrated correctly:
fzf --version
Expected output (version will vary):
0.54.3 (brew)
Then open a new terminal and press Ctrl-R. If the fzf history search opens rather than the default readline reverse search, integration is working.
Troubleshooting
- Ctrl-R still opens the old readline search. The integration script wasn't sourced. Verify the
sourcelines are present in your RC file, that the paths are correct for your distro, and that you've opened a fresh terminal session. - No files appear. The default finder uses
find; ifFZF_DEFAULT_COMMANDis set tofdandfdisn't installed, fzf will show nothing. Either installfd(apt install fd-find/dnf install fd-find/pacman -S fd) or unset the variable. - Preview pane is blank. The preview command (
bat,git show, etc.) must be on your PATH. Run it manually against a sample argument to confirm it works. - Alt-C does nothing on a Wayland terminal. Some terminal emulators intercept Alt key combinations. Check your terminal's key binding settings, or remap the binding:
export FZF_ALT_C_COMMAND='fd --type d'and rebind withbind -x '"\ec": fzf-cd-widget'in Bash. - fzf version from apt is too old. Install via Git as shown above. The Git installer places binaries in
~/.fzf/bin/and prepends it to your PATH automatically.
Frequently asked questions
- Does fzf work inside tmux or multiplexers?
- Yes. fzf detects tmux and can open in a tmux popup instead of inline by setting FZF_TMUX=1 or using the fzf-tmux wrapper script that ships with fzf. Set FZF_TMUX_OPTS='-p 80%,60%' to control popup dimensions.
- Can I use fzf with multiple selections to act on many files at once?
- Pass --multi to fzf and use Tab to mark items. The selections are printed one per line, so you can pipe them to xargs or a loop to act on all of them at once.
- How do I make fzf ignore .gitignored files and hidden directories?
- Switch to fd as your default command with FZF_DEFAULT_COMMAND='fd --type f'. fd respects .gitignore by default and skips hidden files unless you add --hidden.
- Is fzf safe to use in scripts, or is it only for interactive use?
- fzf requires an interactive terminal (a TTY) for its UI. In scripts that run non-interactively, fzf will fail with an error. Use it only in interactive shell functions or wrappers that a human invokes directly.
- How do I change the fzf color scheme to match my terminal theme?
- Add --color options to FZF_DEFAULT_OPTS. For example, --color=bg+:#313244,fg+:#cdd6f4 sets selection colors. The fzf wiki lists full Catppuccin, Dracula, and other popular theme configurations.
Related guides
Bash Arrays and Associative Arrays
Master bash indexed and associative arrays: declaration, element access, looping, mapfile, namerefs, and practical patterns for real scripting work.
Bash Functions and Variable Scoping
Master Bash function scoping with local variables, source-based libraries, correct use of return codes, and array passing techniques including namerefs.
Bash Loops: for, while and until
Learn all three Bash loop types — for, while, and until — with practical, copy-paste examples covering file iteration, counting, polling, and safe line reading.
Bash Scripting for Beginners
Learn Bash scripting from scratch: shebang lines, variables, conditionals, loops, and arguments, plus a real backup script to tie it all together.