NexusCS

fzf

CLI
Quick reference for fzf - a blazing fast command-line fuzzy finder for interactive filtering of any list including files, command history, and processes.
featured

Getting started

Installation

# macOS
brew install fzf

# Ubuntu/Debian
sudo apt install fzf

# Install shell integration
$(brew --prefix)/opt/fzf/install  # macOS
/usr/share/doc/fzf/examples/install  # Linux

Basic usage

fzf                    # Search files in current dir
cat file | fzf         # Search piped input
vim $(fzf)            # Open selected file in vim
cd $(find * -type d | fzf)  # Select directory

Quick example

# Find and kill process
ps aux | fzf | awk '{print $2}' | xargs kill

# Search command history
history | fzf

# Search files and preview
fzf --preview 'cat {}'

Keybindings

Default keybindings

Key Action
Ctrl+J / Ctrl+N / Move down
Ctrl+K / Ctrl+P / Move up
Enter Select and exit
Ctrl+C / Esc Cancel and exit
Tab Mark multiple items
Shift+Tab Unmark items
Ctrl+A Select all
Ctrl+D Deselect all

Additional navigation

Key Action
Alt+A Toggle all
Alt+Enter Select and continue
PageUp Page up
PageDown Page down
Ctrl+U Clear query
Ctrl+W Delete word
Alt+B Move word backward
Alt+F Move word forward

Search syntax

Basic patterns

word          # Fuzzy match
'word         # Exact match (quoted)
^word         # Prefix exact match
word$         # Suffix exact match
!word         # Inverse match (exclude)

Multiple terms

word1 word2   # AND (both must match)
word1 | word2 # OR (either matches)
word1 !word2  # AND NOT

Advanced patterns

^core go$ | rb$ !git  # Complex query
'wild         # Exact prefix match
.md$          # Suffix with special char
^music        # Starts with music
!^__          # Not starting with __

Command options

Search behavior

-e, --exact          # Exact match (disable fuzzy)
-i, --ignore-case    # Case insensitive
+i, --no-ignore-case # Case sensitive
--algo TYPE          # Algorithm: v1|v2 (default: v2)
-n, --nth N          # Comma-separated field indices
--with-nth N         # Transform display with fields

Interface options

-m, --multi          # Enable multi-select
--no-multi           # Disable multi-select
--height N%          # Height of window (40%)
--min-height N       # Minimum height
--layout LAYOUT      # default|reverse|reverse-list
--reverse            # Reverse layout
--border             # Draw border
--no-border          # No border

Preview window

--preview CMD        # Preview command
--preview-window POS # right|down|left|up[:SIZE]
--preview-window hidden  # Start hidden
--preview-window wrap    # Wrap long lines
--preview-window nowrap  # No wrap

Shell integration

Bash/Zsh keybindings

Key Action
Ctrl+T Paste selected files to command line
Ctrl+R Search command history
Alt+C cd into selected directory

After running install script, these work automatically.

Custom key bindings

# In ~/.bashrc or ~/.zshrc

# Ctrl+F to search files
bind '"\C-f": "$(fzf)\e\C-e\er"'  # Bash
bindkey -s '^f' '$(fzf)\n'        # Zsh

# Custom cd
export FZF_ALT_C_COMMAND='find . -type d'
export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -50'"

Environment variables

Core variables

# Default command to generate list
export FZF_DEFAULT_COMMAND='fd --type f'

# Default options for all fzf instances
export FZF_DEFAULT_OPTS='
  --height 40%
  --layout reverse
  --border
  --preview "cat {}"
'

Shell integration variables

# Ctrl+T file search
export FZF_CTRL_T_COMMAND='fd --type f --hidden'
export FZF_CTRL_T_OPTS="--preview 'bat --color=always {}'"

# Alt+C directory search
export FZF_ALT_C_COMMAND='fd --type d --hidden'
export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -50'"

# Ctrl+R history search
export FZF_CTRL_R_OPTS='
  --preview "echo {}"
  --preview-window down:3:wrap
'

Color scheme

# Dracula theme
export FZF_DEFAULT_OPTS='
  --color=fg:#f8f8f2,bg:#282a36,hl:#bd93f9
  --color=fg+:#f8f8f2,bg+:#44475a,hl+:#bd93f9
  --color=info:#ffb86c,prompt:#50fa7b,pointer:#ff79c6
  --color=marker:#ff79c6,spinner:#ffb86c,header:#6272a4
'

Preview window

Preview setup

# Basic preview
fzf --preview 'cat {}'

# Preview with bat (syntax highlighting)
fzf --preview 'bat --color=always {}'

# Preview with file info
fzf --preview 'file {}; echo "---"; head -50 {}'

# Conditional preview
fzf --preview '[[ -f {} ]] && bat {} || tree -C {}'

Preview positioning

--preview-window right      # Right side (default)
--preview-window right:50%  # Right, 50% width
--preview-window down       # Bottom
--preview-window down:40%   # Bottom, 40% height
--preview-window up:30%     # Top, 30% height
--preview-window left:40%   # Left, 40% width

Preview controls

--preview-window hidden        # Start hidden
--preview-window hidden:right  # Hidden, right when shown
--preview-window wrap          # Wrap long lines
--preview-window nowrap        # Don't wrap
--preview-window nohidden      # Always visible

# Toggle preview with Ctrl+P
--bind 'ctrl-p:toggle-preview'

# Scroll preview
--bind 'ctrl-d:preview-page-down'
--bind 'ctrl-u:preview-page-up'

Common patterns

Git integration

# Checkout git branch
git branch | fzf | xargs git checkout

# Show git log and view commit
git log --oneline | fzf | awk '{print $1}' | xargs git show

# Git add files interactively
git status -s | fzf -m | awk '{print $2}' | xargs git add

# Better git checkout with preview
fco() {
  git branch --all | grep -v HEAD |
  fzf --preview 'git log --oneline --color {1}' |
  sed 's/.* //' | sed 's#remotes/[^/]*/##' |
  xargs git checkout
}

File operations

# Find and edit file
fe() {
  local file
  file=$(fzf --preview 'bat --color=always {}') && vim "$file"
}

# Find and cd to directory
fcd() {
  local dir
  dir=$(find ${1:-.} -type d 2>/dev/null | fzf) && cd "$dir"
}

# Find and delete files
frm() {
  find . -type f | fzf -m | xargs rm -v
}

Process management

# Kill process interactively
fkill() {
  local pid
  pid=$(ps aux | sed 1d | fzf -m | awk '{print $2}')
  if [ -n "$pid" ]; then
    echo "$pid" | xargs kill -${1:-9}
  fi
}

# SSH to host
fssh() {
  local host
  host=$(grep "^Host " ~/.ssh/config | cut -d ' ' -f 2 | fzf)
  [ -n "$host" ] && ssh "$host"
}

Advanced usage

Custom bindings

# Multi-action bindings
fzf --bind 'ctrl-y:execute-silent(echo {} | pbcopy)' \
    --bind 'ctrl-e:execute(vim {})' \
    --bind 'ctrl-d:execute(rm {})' \
    --bind 'ctrl-o:execute(open {})'

# Change directory on delete
fzf --bind 'ctrl-d:reload(find . -type f)'

# Custom actions
fzf --bind 'enter:execute(less {})+abort'

With ripgrep

# Search file contents with preview
rg --color=always --line-number --no-heading --smart-case "${*:-}" |
  fzf --ansi \
      --color "hl:-1:underline,hl+:-1:underline:reverse" \
      --delimiter : \
      --preview 'bat --color=always {1} --highlight-line {2}' \
      --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'

# Fuzzy search in files
rgf() {
  rg --line-number --no-heading --color=always --smart-case "$@" |
    fzf --ansi --preview 'bat --color=always {1} --highlight-line {2}'
}

Multi-select with preview

# Select multiple files to open
selected=$(fzf -m \
  --preview 'bat --color=always {}' \
  --preview-window right:60%:wrap \
  --bind 'ctrl-a:select-all' \
  --bind 'ctrl-d:deselect-all' \
  --bind 'ctrl-t:toggle-all')

echo "$selected" | xargs -o vim

Inline mode

# Small inline window
export FZF_DEFAULT_OPTS='--height 40% --layout reverse --inline-info'

# Tmux popup (requires tmux 3.2+)
export FZF_DEFAULT_OPTS='--tmux'

# Custom tmux popup size
fzf-tmux -p 80%,60%  # 80% width, 60% height

Performance tips

Faster file finding

# Use fd instead of find
export FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git'

# Use ripgrep for content search
export FZF_DEFAULT_COMMAND='rg --files --hidden --glob "!.git"'

# Ignore patterns
export FZF_DEFAULT_COMMAND='fd --type f --hidden \
  --exclude .git --exclude node_modules --exclude .cache'

Optimize preview

# Limit preview size
--preview 'head -100 {}'

# Conditional preview (files only)
--preview '[[ -f {} ]] && bat {}'

# Cache preview results
--preview 'bat --color=always {}' \
--preview-window 'right:50%:+{2}+3/3:~3'

# Disable preview for large files
--preview '[[ $(wc -c < {}) -lt 10000 ]] && bat {}'

Gotchas

Common issues

⚠️ Shell integration not working

# Make sure you ran the install script
$(brew --prefix)/opt/fzf/install  # macOS

# Source in your shell config
[ -f ~/.fzf.bash ] && source ~/.fzf.bash  # Bash
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh    # Zsh

⚠️ Preview not showing colors

# Use --ansi flag for colored input
rg --color=always "pattern" | fzf --ansi

# Or use bat for syntax highlighting
fzf --preview 'bat --color=always {}'

Performance pitfalls

⚠️ Slow on large directories

# Don't use plain find
# ❌ find . -type f | fzf

# Use fd or ripgrep instead
# ✅ fd --type f | fzf
# ✅ rg --files | fzf

# Limit depth
fd --type f --max-depth 3 | fzf

⚠️ Preview causes lag

# Don't preview huge files
# ❌ fzf --preview 'cat {}'

# Limit preview output
# ✅ fzf --preview 'head -100 {}'

# Check file size first
fzf --preview '[[ $(wc -c < {}) -lt 100000 ]] && bat {}'

Configuration examples

Complete .zshrc setup

# ~/.zshrc

# Install fzf
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh

# Use fd for faster search
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'

# Default options
export FZF_DEFAULT_OPTS='
  --height 60%
  --layout reverse
  --border
  --inline-info
  --color fg:#f8f8f2,bg:#282a36,hl:#bd93f9
  --color fg+:#f8f8f2,bg+:#44475a,hl+:#bd93f9
  --color info:#ffb86c,prompt:#50fa7b,pointer:#ff79c6
  --bind ctrl-a:select-all
  --bind ctrl-d:deselect-all
  --bind ctrl-t:toggle-all
  --bind ctrl-p:toggle-preview
  --preview-window=:hidden
'

# Ctrl+T: File search with preview
export FZF_CTRL_T_OPTS="
  --preview 'bat --color=always --line-range :500 {}'
  --preview-window right:50%:wrap
"

# Alt+C: Directory search with tree preview
export FZF_ALT_C_OPTS="
  --preview 'tree -C {} | head -50'
  --preview-window right:50%
"

# Custom functions
fe() {
  local files
  files=$(fzf --multi --preview 'bat --color=always {}') && vim ${files}
}

fcd() {
  local dir
  dir=$(fd --type d --hidden --follow --exclude .git | fzf) && cd "$dir"
}

fkill() {
  local pid
  pid=$(ps aux | sed 1d | fzf -m | awk '{print $2}')
  [ -n "$pid" ] && echo "$pid" | xargs kill -${1:-9}
}

# Git integration
fco() {
  local branch
  branch=$(git branch --all | grep -v HEAD |
    fzf --preview 'git log --oneline --color {1} | head -50') &&
  git checkout $(echo "$branch" | sed 's/.* //' | sed 's#remotes/[^/]*/##')
}

Also see