- cli
- l1
- topic-pack
- fzf --- Portal | Level: L1: Foundations | Topics: fzf | Domain: CLI Tools
fzf — Fuzzy Finder Primer¶
Why This Matters¶
fzf turns any list into an interactive, filterable menu. Piping command output through fzf eliminates slow manual scanning of logs, process lists, git branches, and Kubernetes resources. Once you wire it into your shell, every lookup operation becomes sub-second.
Name origin: fzf = fuzzy finder. Written in Go by Junegunn Choi, first released in 2013. It has 65,000+ GitHub stars, making it one of the most popular CLI tools ever created.
Fun fact: fzf integrates directly with bash/zsh: Ctrl+R fuzzy-searches command history (instead of the default backward search), Ctrl+T inserts a file path, and Alt+C changes to a directory. These bindings alone are worth the install.
Core Concepts¶
Basic Usage¶
fzf reads lines from stdin and presents an interactive fuzzy-match selector:
# Pick a file from the current tree
find . -type f | fzf
# Pick a running process
ps aux | fzf
# Pick a Kubernetes pod
kubectl get pods -o name | fzf
The search is fuzzy by default — typing mncfg matches main_config.yaml. Use a single quote prefix for exact matching: 'exact.
Search Syntax¶
| Token | Meaning |
|---|---|
sbtrkt |
Fuzzy match |
'wild |
Exact match |
^music |
Prefix exact match |
.mp3$ |
Suffix exact match |
!fire |
Inverse match |
!^music |
Inverse prefix |
Combine tokens with spaces (AND logic): ^src .go$ !test.
Piping and Filtering¶
fzf shines when combined with pipes:
# Search environment variables
env | fzf
# Grep results as selectable list
grep -rn "ERROR" /var/log/ | fzf
# Select and kill a process
kill -9 $(ps aux | fzf | awk '{print $2}')
# Select a docker container to exec into
docker exec -it $(docker ps --format '{{.Names}}' | fzf) bash
Multi-Select¶
Pass --multi (or -m) to select multiple items with Tab:
# Select multiple files to delete
rm $(find /tmp -type f -mtime +30 | fzf -m)
# Select multiple pods to describe
kubectl get pods -o name | fzf -m | xargs -I{} kubectl describe {}
Preview Window¶
The --preview flag shows a live preview of the selected item:
# File preview with syntax highlighting (requires bat)
fzf --preview 'bat --color=always {}'
# Pod preview
kubectl get pods -o name | fzf --preview 'kubectl describe {}'
# Git log preview
git log --oneline | fzf --preview 'git show {1}'
Control preview layout:
fzf --preview 'cat {}' --preview-window=right:60%:wrap
fzf --preview 'cat {}' --preview-window=up:40%:hidden --bind '?:toggle-preview'
Shell Integration¶
Remember: The three fzf shell bindings: "R-T-C" — Ctrl-R (history search), Ctrl-T (file path insert), Alt-C (cd to directory). These three bindings replace the default shell behaviors with fuzzy-matching equivalents.
History Search (Ctrl-R)¶
fzf replaces the default reverse history search:
Now Ctrl-R opens a fuzzy-searchable command history.
Directory Navigation (Alt-C)¶
Alt-C fuzzy-searches directories and cds into the selection.
File Completion (Ctrl-T)¶
Ctrl-T inserts a fuzzy-selected file path at the cursor.
Keybindings¶
Custom bindings inside the fzf interface:
fzf --bind 'ctrl-y:execute-silent(echo {} | pbcopy)' \
--bind 'ctrl-e:execute(vim {})' \
--bind 'ctrl-d:half-page-down' \
--bind 'ctrl-u:half-page-up'
Git Integration¶
# Checkout a branch interactively
git branch -a | fzf | xargs git checkout
# Interactive git log browser
git log --oneline --all | fzf --preview 'git show --stat {1}'
# Stage files interactively
git diff --name-only | fzf -m | xargs git add
Kubectl Integration¶
# Switch namespace
kubectl get ns -o name | sed 's|namespace/||' | fzf | xargs kubectl config set-context --current --namespace
# Tail logs from a selected pod
kubectl get pods -o name | fzf | xargs -I{} kubectl logs -f {}
# Exec into a selected container
kubectl get pods -o name | fzf --preview 'kubectl get {} -o yaml' | xargs -I{} kubectl exec -it {} -- sh
Environment Variables¶
| Variable | Purpose |
|---|---|
FZF_DEFAULT_COMMAND |
Command used to generate input (e.g., fd --type f) |
FZF_DEFAULT_OPTS |
Default options applied to every invocation |
FZF_CTRL_T_COMMAND |
Command for Ctrl-T file finder |
FZF_ALT_C_COMMAND |
Command for Alt-C directory finder |
Under the hood:
FZF_DEFAULT_COMMANDonly applies when fzf is invoked without stdin piped to it. When you runfind . | fzf, theFZF_DEFAULT_COMMANDis ignored because stdin is already connected. This is by design — the environment variable provides a default source when fzf has nothing piped in.
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
Practical Patterns¶
Combining with Other Tools¶
# fd + fzf + bat
fd --type f | fzf --preview 'bat --color=always {}'
# rg + fzf (search then select)
rg --line-number "TODO" | fzf --delimiter=: --preview 'bat --color=always {1} --highlight-line {2}'
Tips¶
- Use
fdorrg --filesasFZF_DEFAULT_COMMANDinstead offind— 5-10x faster - Set
--height 40%to avoid full-screen takeover in quick lookups - Use
--ansiwhen piping colored output
Gotcha: fzf reads the entire input before displaying results. If you pipe a very slow command (e.g.,
find /on a massive filesystem), fzf will appear to hang. Usefdinstead offindfor filesystem searches — it respects.gitignore, skips hidden directories by default, and is 5-10x faster.One-liner: The single most useful fzf alias for DevOps:
alias kp='kubectl get pods -A -o name | fzf --preview "kubectl describe {}" | xargs kubectl delete'— interactive pod killer with preview. Adjust the final command to taste.
Wiki Navigation¶
Related Content¶
- Modern CLI Drills (Drill, L0) — fzf
- Modern CLI Tools (Topic Pack, L0) — fzf
- Skillcheck: Modern CLI Tools (Assessment, L0) — fzf
- fzf Flashcards (CLI) (flashcard_deck, L1) — fzf