I use fzf for everything. Finding files, searching history, switching git branches, picking Docker containers. If it involves choosing something from a list, I pipe it through fzf. It is the single most useful CLI tool I have installed in the last ten years, and I am not exaggerating.
fzf is a general-purpose command-line fuzzy finder. You give it a list, it gives you an interactive search. That is the whole idea. No complicated flags, no config files, no learning curve. Type some characters, get matches, press Enter.
Installing fzf
Install it once, use it forever. Here are the options.
# macOS
brew install fzf
# Ubuntu/Debian
sudo apt install fzf
# Or clone directly ( gives you shell integration too )
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/installThe git clone method is what I prefer because the install script sets up keybindings and completion automatically. Say yes to everything it asks.
The Three Keybindings That Changed My Life
After running the install script, you get three keybindings. These are the ones you will actually use.
1. Ctrl+T - Find files and paste the path
2. Ctrl+R - Search command history interactively
3. Alt+C - cd into a directory you fuzzy-match( I know, Alt+C on Mac is Option+C. It works. )
Ctrl+R alone is worth the install. I used to type `history | grep long_command_name` and copy-paste the result. Now I press Ctrl+R, type three letters, and the command is there. Game changer.
Replacing Every Picker With fzf
Here is where fzf gets addictive. Any command that needs you to pick something can use fzf as the interface.
# Switch git branches interactively
git checkout $(git branch -a | fzf)
# Kill a Docker container without remembering names
docker kill $(docker ps --format '{{.Names}}' | fzf)
# Open a file in vim from anywhere
vim $(fzf)
# Pick a process to kill
kill $(ps aux | fzf | awk '{print $2}')
# Select a SSH host from your config
ssh $(grep '^Host ' ~/.ssh/config | awk '{print $2}' | fzf)Each of these replaces something I used to do by typing partial names and tab-completing. fzf is faster because I only need to remember two characters of the target, not the whole name.
fzf With tmux: The Real Setup
fzf has a built-in tmux integration that opens the finder in a split pane. This is how I actually use it day to day.
# Enable tmux integration
export FZF_TMUX=1
export FZF_TMUX_OPTS='-p80%,60%'
# Now Ctrl+T, Ctrl+R, Alt+C open in a popup pane
# This is the correct way to use fzf in tmuxThe popup pane keeps your main terminal intact. You search, you pick, the result drops into your current prompt. No screen switching, no context loss.
Customizing the Preview
fzf shows a preview window. This alone makes it better than every other picker because you can see what you are selecting before you select it.
# Preview files with bat ( syntax highlighting )
export FZF_CTRL_T_OPTS='--preview "bat --style=numbers --color=always {} 2>/dev/null || cat {}" --preview-window=right:60%'
# Preview directories with tree
export FZF_ALT_C_OPTS='--preview "tree -C {} | head -50"'
# Preview Docker containers
docker ps -a --format '{{.Names}}' | fzf --preview 'docker inspect {1}' --preview-window=right:50%The preview window turns fzf from a search tool into a decision tool. You do not just find things. You confirm they are the right things before committing.
Advanced: fzf as a Vim Plugin
fzf has a Vim plugin. If you use Vim ( and you should ), this is mandatory.
" Install ( vim-plug )
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'
" File finder
nnoremap <C-p> :Files<CR>
" Buffer switcher
nnoremap <Leader>b :Buffers<CR>
" Ripgrep + fzf ( the only search setup you need )
command! -bang -nargs=* Rg call fzf#vim#grep('rg --column --line-number --no-heading --color=always --smart-case '.shellescape(<q-args>), 1, {'options': '--delimiter : --nth 4..'}, <bang>0):Files with fzf preview is faster than any IDE file tree. I stopped using NERDTree after a week.
The fzf Pipeline Pattern
The pattern I use most is: generate a list, pipe to fzf, capture the selection, do something with it. This is a template that works for everything.
# Generic fzf pipeline
result=$(some_command | fzf --prompt='Pick> ' --height=40%)
if [ -n "$result" ]; then
do_something_with "$result"
fiI have scripts that follow this pattern for Kubernetes pods, AWS instances, database tables, even Jira tickets. The fzf part never changes. Only the input command and the action change.
Conclusion
fzf removed the part of my workflow where I type things more than once. History search, file finding, branch switching, process killing, SSH connecting. All of it is now three keystrokes and a fuzzy match. If you install one CLI tool this year, make it this one. https://github.com/junegunn/fzf