Find anything.
Compose everything.
fzf turns any stream of text into an interactive choice. Learn its small core, then use previews, field extraction, actions, and reloads to build fast terminal interfaces from ordinary Unix commands.
1. Mental model: interactive filter, not file finder
fzf reads candidate records, lets a person narrow and select them, then writes accepted records. It does not inherently know what a file, process, branch, container, or command is. That ignorance makes it reusable.
producer | fzf [options] | consumer
printf '%s\n' alpha beta gamma | fzf
git branch --format='%(refname:short)' | fzf | xargs git switch
1 · Feed
Pipe newline-delimited items into standard input. With terminal input, fzf uses its built-in directory walker or FZF_DEFAULT_COMMAND.
2 · Find
Type a query. fzf ranks fuzzy matches, supports exact/anchored/negative terms, and can select one or many items.
3 · Emit
Enter prints accepted records to standard output. Cancel produces no record and exit status 130.
Three layers worth separating
| Layer | Purpose | Typical tools/options |
|---|---|---|
| Source | Generate complete candidate set | fd, find, rg, git, ps, SQL/JSON tools |
| Interface | Search, rank, preview, select | fzf, --multi, --preview, --bind |
| Effect | Use accepted value | command substitution, loop, while read, become(...) |
2. Install and enable shell integration
Prefer current package from official release channel or package manager. Distribution repositories can lag, so compare fzf --version when an option from this guide is missing.
macOS
brew install fzf
fzf --versionLinux
# Debian/Ubuntu package
sudo apt install fzf
# Or follow official binary/git installShell setup
Modern fzf binaries embed integration scripts. Add one line to shell startup file, then start a new shell.
| Shell | Startup line | Provides |
|---|---|---|
| Zsh | source <(fzf --zsh) | Ctrl+T, Ctrl+R, Alt+C, completion |
| Bash | eval "$(fzf --bash)" | Key bindings and fuzzy completion |
| Fish | fzf --fish | source | Key bindings |
| Nushell | fzf --nushell prints integration script | Follow emitted-script instructions for installed version |
# ~/.zshrc
source <(fzf --zsh)
# Reload now
exec zsh
FZF_CTRL_T_COMMAND, FZF_ALT_C_COMMAND, and integration-specific *_OPTS before sourcing integration. Empty command variables disable corresponding bindings.Quick health check
printf '%s\n' red green blue | fzf --height=40% --border
# type: gr → press Enter → terminal prints: green
3. Tutorial: from list to file launcher in 25 minutes
Work inside any small project directory. Commands inspect or open files; none modify project content unless editor saves changes.
Run candidate list, type gsg, move with arrows or Ctrl+J/Ctrl+K, accept one.
printf '%s\n' git-status-guide.md getting-started.md glossary.md release-notes.md | fzf
- Observe non-contiguous letters can match.
- Try uppercase letter; smart-case makes query case-sensitive.
- Press Esc; observe no output.
Running bare fzf on terminal input invokes built-in walker. Hidden files appear; directories named .git and node_modules are skipped by default.
fzf --height=70% --layout=reverse --border --prompt='file › '
# Explicit source with fd (if installed)
fd --type f --hidden --exclude .git | fzf --scheme=path
Why explicit source? Reproducible scope, easy exclusions, clear ownership of traversal.
fzf --preview 'sed -n "1,200p" {}' \
--preview-window='right,60%,wrap' \
--bind='ctrl-/:toggle-preview'
# Better colorized preview when bat exists
fzf --preview 'bat --color=always --style=numbers --line-range=:300 -- {}' \
--preview-window='right,60%,border-left'
{}becomes shell-quoted current item.--tells command later arguments are filenames, not flags—use it where tool supports it (bat does; macOS BSD sed does not, hence no--above).- Preview changes as focus moves; keep preview command fast and bounded.
# Shell receives one selected path
file=$(fzf) || exit
${EDITOR:-vi} -- "$file"
# Or replace fzf directly; no parsing round-trip
fzf --bind='enter:become(${EDITOR:-vi} -- {})'
execute vs becomeexecute(...) runs command and returns to fzf. become(...) replaces fzf process; natural for final “open this” action.Here ripgrep searches contents; fzf supplies secondary interactive ranking. Records have path:line:column:text fields.
rg --column --line-number --no-heading --color=always --smart-case . |
fzf --ansi --delimiter=: \
--preview 'bat --color=always --highlight-line {2} --line-range=:500 -- {1}' \
--preview-window='right,60%,+{2}/2' \
--bind='enter:become(${EDITOR:-vi} +{2} -- {1})'
--ansiinterprets color codes without matching them.--delimiter=:enables field placeholders.{1}is path;{2}is line number.- Preview offset
+{2}/2places matching line near middle.
printf '%s\n' alpha beta gamma delta | fzf --multi
# Tab marks and moves down; Shift-Tab marks and moves up.
# Enter prints marked rows, or current row when nothing marked.
4. Practice simulator
Browser approximation builds muscle memory without launching terminal. Type fragments; use ↑/↓, Tab, and Enter. Scoring intentionally simplified; real fzf ranking is richer.
5. Query grammar: fuzzy, exact, anchored, negative, OR
Default extended search splits query on unescaped spaces. Terms on same side of | combine with AND; bar separates alternatives. Smart-case is case-insensitive until query contains uppercase.
music..mp3.draft.go or rs.meaning: exact “api” AND begins “src” AND NOT “test” AND ends “.ts” OR ends “.tsx”
--query, quote for shell first. Example: fzf --query='^src !test .ts$'. Interactive input itself is not shell-expanded.Scoring and schemes
--scheme=default: general scoring.--scheme=path: rewards matches after path separators and prioritizes filename portion.--scheme=history: preserves chronological importance using input order.--tiebreak=CRI[,..]: order for tied scores—length(default),chunk,pathname,begin,end,index;indexis implicitly appended last.--exact: exact becomes default; leading apostrophe switches a term back to fuzzy.--no-sort: retain source order while filtering; useful for logs and pre-ranked sources.
Automatic choice: when input comes from terminal (built-in walker or FZF_DEFAULT_COMMAND) and no reload/transform is bound to start, fzf picks path scheme by itself; piped input gets default. Explicit --scheme overrides.
6. Navigation, editing, and selection
Move
--history they navigate fzf query history insteadEdit query
Select
Preview
--multi enables unlimited selection; --multi=3 caps it. If nothing marked, accepting returns current item. Output order follows selected item order as managed by fzf, not necessarily current visual rank—test before relying on ordering.
7. Input/output contract and exit status
| Status | Meaning | Shell implication |
|---|---|---|
0 | Normal acceptance | Use emitted records |
1 | No match—accepting with zero matches, or --filter/--exit-0 finding nothing | Often normal branch |
2 | fzf error | Inspect command/options |
126/127 | become permission/command error | Check executable and permissions |
130 | Interrupted via Esc/Ctrl-C | Treat as user cancellation |
Capture without losing cancel semantics
# Correct: only act when accepted
if choice=$(printf '%s\n' one two three | fzf); then
printf 'selected: %s\n' "$choice"
else
printf 'cancelled\n' >&2
fi
Machine-friendly modes
--filter=QUERY: print matching items and exit; useful for tests/scripts, no interactive UI.--select-1: auto-select if initial result has exactly one match.--exit-0: exit if initial result has no match.--print-query: first output record is query, then selections.--expect=ctrl-e,ctrl-v: first output record identifies accept key; remaining records are choices.--read0 --print0: NUL-delimited input/output for arbitrary filenames.
# GNU/BSD find emits NULs; loop consumes NULs
find . -type f -print0 |
fzf --read0 --print0 --multi |
while IFS= read -r -d '' path; do
printf 'picked: %q\n' "$path"
done
8. Fields, display transforms, accepted values, placeholders
Structured lines often contain machine ID plus human label. fzf can search/display selected fields while preserving or transforming emitted value.
| Option | Controls | Example |
|---|---|---|
--delimiter=REGEX | How fields are split | --delimiter='\t' |
--nth=EXPR | Fields searched | --nth=2.. |
--with-nth=EXPR | Fields displayed | --with-nth=2,3 |
--accept-nth=EXPR | Fields printed on acceptance | --accept-nth=1 |
# input: id TAB name TAB environment
printf '42\tPayments API\tprod\n17\tDocs site\tstaging\n' |
fzf --delimiter=$'\t' --with-nth=2,3 --accept-nth=1
Field expressions
1 first-1 last2.. from second..-2 through second-last3..5 range.. all
Command placeholders
| Placeholder | Expansion | Use |
|---|---|---|
{} | Current item, shell-quoted | --preview 'file -- {}' |
{+} | All selected items, individually quoted; current if none | execute(${EDITOR:-vi} -- {+}) |
{1}, {2..}, {-1} | Fields from original record | Path/line parsing |
{q} | Current query, quoted; accepts field expressions like {q:1} | Dynamic ripgrep reload |
{n} | Zero-based current item index; {+n} for all selected | Index-aware actions |
{f}, {+f} | f flag writes values to temporary file, expands to its path | Selections too large for ARG_MAX |
--with-nth changes presentation. With both --nth and --with-nth, search field expressions apply to transformed display.9. Preview windows: context without commitment
Preview command executes whenever focus changes. It receives placeholders and size variables such as $FZF_PREVIEW_LINES and $FZF_PREVIEW_COLUMNS.
fzf --preview 'bat --color=always --style=plain -- {}' \
--preview-window='right,55%,wrap,border-left' \
--preview-label=' file preview ' \
--bind='ctrl-/:change-preview-window(right,55%|down,45%|hidden|)'
Placement
right, left, up, down, or next; add size like 60%.
Behavior
wrap, follow, hidden, cycle, border-left.
Responsive threshold
Alternative layouts can switch below size threshold. Useful for wide terminal vs narrow pane.
Fixed header
~3 keeps top three preview lines fixed while body scrolls.
Preview the right kind of object
# Directory: tree; file: bat
fzf --preview '
if [ -d {} ]; then
tree -C -L 2 -- {}
else
bat --color=always --style=numbers --line-range=:300 -- {}
fi
'
10. Layout and appearance
Good presentation communicates scope, available actions, and current mode. fzf can run full-screen, occupy terminal height, or open as a floating pane.
| Control | Purpose | Example |
|---|---|---|
--height=70% | Inline finder below cursor; ~ can adapt height to result count | --height='~60%' |
--popup/--tmux | Floating pane in tmux 3.3+ or Zellij 0.44+ | --popup=center,80%,60% |
--layout | Result direction and prompt position | --layout=reverse |
--style | Coherent preset | --style=full:rounded |
| Borders/labels | Separate list, input, header, footer, preview | --input-label=' query ' |
--header/--footer | Instructions and action hints | --footer='Enter open · Esc cancel' |
--ghost | Hint shown in empty query | --ghost='type to filter' |
--wrap/--gap | Long or multi-line record readability | --wrap=word --gap |
--freeze-left/right | Pin structured fields during horizontal scroll | --freeze-left=2 |
--color | Base scheme and named color overrides | --color='dark,hl:#ff9b78' |
fzf --height='~70%' --layout=reverse --style='full:rounded' \
--input-label=' query ' --list-label=' matches ' \
--preview-label=' preview ' --ghost='type to filter' \
--footer='Enter accept · Tab select · Esc cancel'
Raw mode and list fidelity
--raw keeps non-matching items visible with a distinct gutter; matching items remain navigable as matches. --no-sort retains input order, while --tac reverses it. These controls help dashboards/logs where surrounding records and source order carry meaning.
11. Bindings and actions: turn selector into interface
Binding shape: KEY:ACTION. Separate bindings with comma; chain actions with +. Quote whole argument for shell.
fzf --multi \
--bind='ctrl-a:select-all,ctrl-d:deselect-all' \
--bind='ctrl-/:toggle-preview' \
--bind='alt-enter:execute(${EDITOR:-vi} -- {})' \
--bind='enter:become(${EDITOR:-vi} -- {})'
| Action family | Representative actions | Intent |
|---|---|---|
| Finish | accept, abort, become(...) | Exit or replace process |
| Selection | toggle, select-all, deselect-all | Manage multi-selection |
| Process | execute(...), execute-silent(...) | Run effect, optionally return |
| View | toggle-preview, change-preview-window(...) | Change layout/context |
| Query | clear-query, change-query(...), replace-query | Manipulate search |
| Data | reload(...), reload-sync(...) | Replace candidate stream |
| Presentation | change-prompt(...), transform-header(...) | Reflect mode/state |
Action delimiters
Parentheses are readable: execute(vim {}). If command contains parentheses, choose paired delimiter unlikely to conflict: execute[cmd], execute{cmd}, execute~cmd~. Colon form consumes rest of binding and must be last.
Choose effect semantics deliberately
execute(...): visible interactive command; fzf returns afterward.execute-silent(...): no alternate-screen switch; best for quick invisible effect. Still blocks unless command backgrounds itself.become(...): replaces fzf, simplest final launcher, preserves exit behavior better than parsing text throughxargs.
12. Dynamic data: reloads, events, transforms
reload(...) swaps candidates while fzf stays open. Events trigger actions from state changes. Together they create live process pickers, search launchers, log viewers, and dashboards.
Manual process refresh
ps -ef |
fzf --header-lines=1 --layout=reverse --track --id-nth=2 \
--header='Ctrl-R refreshes · Enter prints process row' \
--bind='ctrl-r:reload(ps -ef)'
Interactive ripgrep launcher
RG='rg --column --line-number --no-heading --color=always --smart-case'
fzf --ansi --disabled --query='' \
--bind="start,change:reload:$RG {q} || true" \
--delimiter=: \
--preview='bat --color=always --highlight-line {2} -- {1}' \
--preview-window='right,60%,+{2}/2' \
--bind='enter:become(${EDITOR:-vi} +{2} -- {1})'
--disabled?ripgrep owns content search. fzf passes query to ripgrep through {q} and displays returned records without applying second fuzzy filter. Add key binding to toggle into fzf-only filtering when desired.Useful events
| Event | When | Typical use |
|---|---|---|
start | Once at launch | Initial reload or layout state |
load | Input stream completes | Change “Loading” prompt |
change | Query changes | Reload search results |
result/result-final | Filtering snapshot/final result ready | Count-driven state |
focus | Current row changes | Dynamic labels; keep command fast |
one/zero | One/no match | Auto-accept or fallback reload |
every(N) | Timer interval | Periodic refresh, idle UI |
reload-sync keeps old list until replacement command completes. --track --id-nth=FIELD helps retain focus across reloads by stable identity.
External control with --listen
fzf can accept actions over local HTTP or Unix domain socket. This enables another process to send up, reload(...), or composed actions while interface runs.
# Terminal 1: local Unix socket (path must end in .sock)
# --no-tmux keeps fzf inline even if your defaults enable --popup/--tmux
fzf --listen=/tmp/my-picker.sock --no-tmux
# Terminal 2: send harmless navigation action
curl --unix-socket /tmp/my-picker.sock http -d 'down'
FZF_API_KEY when TCP endpoint needs protection. Safe listener blocks remote-process actions; --listen-unsafe permits them and should not face untrusted clients.13. Built-in shell integration
Ctrl T
Paste selected file paths into current command line. Configure source with FZF_CTRL_T_COMMAND and UI with FZF_CTRL_T_OPTS.
Ctrl R
Search shell command history. Configure interface with FZF_CTRL_R_OPTS. Recent versions can expose raw/history behavior.
Alt C
Select directory and change into it. Configure source with FZF_ALT_C_COMMAND and UI with FZF_ALT_C_OPTS.
Fuzzy completion
In Bash/Zsh integration, type trigger (default **) then Tab in supported contexts:
vim **<Tab> # files/directories
cd **<Tab> # directories
ssh **<Tab> # hostnames
kill -9 **<Tab> # processes
export **<Tab> # variables
Customize before sourcing
# ~/.zshrc, before source <(fzf --zsh)
export FZF_CTRL_T_OPTS="--preview 'bat --color=always --style=numbers -- {}'"
export FZF_ALT_C_OPTS="--preview 'tree -C -L 2 -- {}'"
export FZF_CTRL_R_OPTS="--height=60% --layout=reverse --border"
source <(fzf --zsh)
14. Configuration: defaults without surprising scripts
FZF_DEFAULT_OPTS applies everywhere—interactive commands, scripts, plugins, shell integration. Keep universal defaults visual and conservative. Put workflow behavior in aliases/functions.
# Safe-ish global presentation
export FZF_DEFAULT_OPTS='
--height=70%
--layout=reverse
--border
--info=inline-right
--cycle
--bind=ctrl-/:toggle-preview
'
# Alternative: keep defaults in a file, parsed like FZF_DEFAULT_OPTS
export FZF_DEFAULT_OPTS_FILE="$HOME/.fzfrc"
--multi, --expect, --print-query, --read0, custom Enter, or broad --bind can break consumers expecting ordinary output.Reusable function pattern
# Zsh/Bash: choose Git branch and switch
fbr() {
local branch
branch=$(git for-each-ref --format='%(refname:short)' refs/heads |
fzf --scheme=path --prompt='branch › ' \
--preview='git log --color=always --oneline --decorate -20 {}') || return
git switch -- "$branch"
}
Function owns source, UI, cancel branch, and effect. Easier to test than dense alias; avoids global side effects.
15. Practical recipes
Open one or many files
fzf --multi \
--preview='bat --color=always --style=numbers --line-range=:300 -- {}' \
--bind='enter:become(${EDITOR:-vi} -- {+})'Change directory with preview
cdir() {
local dir
dir=$(find . -type d -not -path '*/.git/*' |
fzf --scheme=path --preview='ls -la -- {}') || return
cd -- "$dir" || return
}Switch Git branch
branch=$(git for-each-ref --sort=-committerdate \
--format='%(refname:short)\t%(committerdate:relative)\t%(subject)' refs/heads |
fzf --delimiter=$'\t' --with-nth=1,2,3 --accept-nth=1 \
--preview='git log --color=always --oneline --decorate -30 {1}') || exit
git switch -- "$branch"Browse Git commits
git log --color=always --format='%C(yellow)%h%Creset %C(cyan)%ad%Creset %s%C(auto)%d' --date=short |
fzf --ansi --no-sort --scheme=history \
--preview='git show --color=always {1}' \
--bind='enter:become(git show --color=always {1} | less -R)'Search repository text and open line
rg --column --line-number --no-heading --color=always --smart-case . |
fzf --ansi --delimiter=: \
--preview='bat --color=always --highlight-line {2} -- {1}' \
--preview-window='right,60%,+{2}/2' \
--bind='enter:become(${EDITOR:-vi} +{2} -- {1})'Choose process, review, then send TERM
pid=$(ps -eo pid,user,%cpu,%mem,command |
fzf --header-lines=1 --layout=reverse --prompt='process › ' \
--preview='ps -p {1} -o pid,ppid,user,%cpu,%mem,lstart,command' \
--accept-nth=1) || exit
kill -TERM "$pid"TERM; reserve KILL for processes that cannot shut down cleanly. Confirm PID and owner.Inspect environment variable
name=$(env | cut -d= -f1 | sort | fzf --prompt='env › ') || exit
printf '%s=%s\n' "$name" "${!name}" # Bash indirect expansionPick Docker container
id=$(docker ps --format '{{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}' |
fzf --delimiter=$'\t' --with-nth=2.. --accept-nth=1 \
--preview='docker logs --tail 100 {1} 2>&1') || exit
docker exec -it "$id" shBrowse recent directories from zoxide
# Function so cd affects your shell and `return` is valid
zd() {
local dir
dir=$(zoxide query --list |
fzf --scheme=path --preview='ls -la -- {}') || return
cd -- "$dir" || return
}Use fzf as noninteractive fuzzy filter
printf '%s\n' src/app.ts src/app.test.ts docs/api.md |
fzf --filter='app !test'
# suitable for assertions; exits 1 when nothing matches16. Safety, quoting, and portability
Quote shell variables
Use "$choice", never bare $choice. Add -- before path arguments where supported.
Use placeholders
fzf shell-quotes {}/{+}. Do not wrap placeholder in extra quotes unless exact command requires it.
Avoid parsing display text
Carry stable ID as field; show friendly fields; emit ID with --accept-nth.
Treat preview as code
Preview/action templates execute shell. Candidate text can be hostile; placeholder quoting limits injection, not target-command behavior.
Common unsafe shape
# Fragile: word splitting, option injection, cancel ambiguity
rm $(find . -type f | fzf --multi)
# Safer: NUL records + explicit loop + --
find . -type f -print0 | fzf --read0 --print0 --multi |
while IFS= read -r -d '' path; do
printf 'would remove: %q\n' "$path" # review first
done
Portability notes
- macOS ships BSD tools; GNU-only flags may fail.
sed -n,find -print0, and quoted shell loops travel better—but BSD sed rejects--end-of-options, so omit it there. bat,fd,rg,tree,zoxideare optional companions, not fzf requirements.- Action commands run through
$SHELL -con Unix. Script snippets needing Bash should declare Bash. - Terminal key encodings vary; some
Ctrl/modified bindings cannot be distinguished.
17. Performance and large/streaming inputs
- Stream early. fzf begins rendering before producer finishes unless
--sync. - Let specialized search tools search. Use ripgrep for file contents; fzf for interactive narrowing.
- Bound infinite streams.
--tail=100000 --tac --no-sort --exactlimits memory and shows newest records first. - Keep previews cheap. Limit lines; avoid repeated network/API calls on focus.
- Avoid unnecessary transforms.
--with-nthretains original lines and increases memory use. - Choose algorithm only with evidence. Default v2 optimizes ranking;
--algo=v1trades optimal scoring for speed.
# Follow logs, retain latest 100k records
tail -f app.log |
fzf --tail=100000 --tac --no-sort --exact \
--preview-window='down,40%,follow' --preview='printf "%s\n" {}'
18. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Bare fzf lists unexpected files | Built-in walker scope/defaults | Pipe explicit producer or tune --walker, --walker-root, --walker-skip. |
| Colors show as escape codes | Colored input without ANSI parsing | Add --ansi. |
| Preview breaks on spaces | Manual interpolation/quoting | Use fzf placeholders and --. |
| Preview painfully slow | Expensive focus-triggered command | Bound output, cache results, move work to source. |
| Script acts after Esc | Ignored exit status/empty substitution | Use choice=$(...) || return or if. |
| Binding parse error | Nested delimiters/commas | Use alternate action delimiter; quote complete --bind. |
| Ctrl T does nothing | Integration not loaded, variable disabled, terminal conflict | Run fzf --zsh/--bash check; inspect startup order/key mapping. |
| Option “unknown” | Older package version | Check fzf --version, fzf --help; update or use older equivalent. |
| Selected display text corrupts ID | Presentation and output conflated | Use delimiter + --with-nth + --accept-nth. |
| Reload empties list during slow query | Asynchronous reload | Use reload-sync when retaining old list matters. |
Debug in layers
- Run producer alone. Confirm records and delimiters.
- Pipe into plain
fzf. Confirm matching/selection. - Add display/field options. Confirm accepted output using
| od -cor| sed -n l. - Add preview. Replace command temporarily with
printf '%s\n' {}. - Add bindings one at a time.
- Add final effect only after inspecting exact emitted value.
19. Exercises: build fluency
Starter · Color picker
Feed 8 color names, select one, print sentence. Handle Esc without printing selection.
One solution
if color=$(printf '%s\n' red orange yellow green blue indigo violet black | fzf); then
printf 'You chose %s.\n' "$color"
fiStarter · Exact and negative
Create path list. Query only Markdown files under docs, excluding archive.
Query
^docs !archive .md$
Intermediate · ID/label split
Create tab-separated service ID, name, status. Search name/status, display both, emit only ID.
Options
--delimiter=$'\t' --with-nth=2,3 --accept-nth=1
Intermediate · Git branch switcher
Sort by commit date, preview 20 commits, return on Esc, switch accepted branch.
Advanced · Dual-mode search
Start with ripgrep owning query; bind key to stop reload and enable fzf search; update prompt to show current mode.
Advanced · Live process board
Refresh every 2 seconds, retain cursor by PID, preview details, require explicit confirmation before signal.
20. Retrieval quiz
Answer aloud before revealing. Mark honestly; score persists locally in this browser.
src, excluding test, ending .ts or .tsx?^src !test .ts$ | .tsx$ — terms AND within each side of the bar; bar separates OR alternatives.execute(...) and become(...)?execute runs the command and returns to fzf. become replaces the fzf process—natural for a final “open this” action.become permission/command errors.)id/name/status rows: show name+status, emit only id—options?--delimiter=$'\t' --with-nth=2,3 --accept-nth=1.{}, {+}, and {q} expand to?{} current item, shell-quoted. {+} all selected items (current if none marked). {q} current query.--disabled?{q} to it via reload on change and must not apply a second fuzzy filter over the results.find . -type f -print0 | fzf --read0 --print0 --multi | while IFS= read -r -d '' path; … — NUL delimiters end-to-end, review before destructive action.--with-nth transforms display, which line do preview placeholders read? Which do --nth expressions read?--nth search expressions apply to the transformed display line.reload-sync(...) retains the old list until the new stream completes; --track --id-nth=FIELD retains focus by stable identity.'foo' (quotes on both ends) match?foo with both ends at word boundaries; underscore also counts as a boundary (unlike regex \b).--tail=N caps items kept in memory; combine with --tac --no-sort to show newest first in source order.FZF_CTRL_T_COMMAND to an empty string before sourcing integration?FZF_ALT_C_COMMAND).21. One-page cheat sheet
Queries
abc fuzzy'abc exact^abc prefixabc$ suffix!abc excludea | b ORa b AND
Core UI
Ctrl J/K move
Enter accept
Tab mark + down
Shift Tab mark + up
Esc cancel
Shift ↑/↓ preview scroll
Fields
-d delimiter--nth search--with-nth display--accept-nth output{1} field{+} selections{q} query
Build UI
--preview context--bind behaviorexecute run + returnbecome replacereload new data--disabled selector mode
Safe shell
Capture status
Quote "$value"
Use --
NUL: --read0 --print0
Separate display from ID
Learn installed build
fzf --versionfzf --helpfzf --manman fzf
# Universal starting pattern
choice=$(producer | fzf --prompt='choose › ' --preview='inspect {}') || exit
consumer -- "$choice"
22. Sources and version note
This guide prioritizes installed fzf 0.74.2 help/man page, then official project documentation. Features differ across releases; use local fzf --man as authority for installed binary.
- Official fzf repository and README — installation, shell integration, core examples.
- Official advanced examples — reloads, ripgrep, previews, Git and process workflows.
- Official changelog — feature/version history.
fzf --helpandfzf --man— option, action, event, environment, placeholder, and exit-status semantics for local 0.74.2 binary.
Guide examples target POSIX-ish shell where practical and label Bash/Zsh assumptions. Optional tools: ripgrep (rg), bat, fd, tree, zoxide, Git, Docker.
Printed from local fzf field guide.