The interactive line picker
fzf reads stdin, shows an interactive prompt where you type to filter, and prints the selected line(s) on stdout. Once integrated into your shell, it transforms history search, file pickers, and process selection into a single muscle-memory.
Install + integrate
brew install fzf
$(brew --prefix)/opt/fzf/install # adds keybindings + completionShell integration and its key bindings vary by fzf version and installation method. Follow the documentation installed with the version you use, then verify which component owns each key:
- Ctrl+R — fuzzy history search. Replaces the default. Type any substring; matches show; Enter to run.
- Ctrl+T — fuzzy file picker. Type at a prompt, hit Ctrl+T, pick a file, the path inserts into the command line.
- Alt+C — fuzzy cd into a subdirectory.
Standalone use
# Inspect a selected process before choosing any signal
pid=$(ps -axo pid=,command= | fzf | awk '{print $1}')
ps -p "$pid" -o pid=,ppid=,user=,command=
# Switch a selected local branch with modern Git
branch=$(git for-each-ref --format='%(refname:short)' refs/heads | fzf)
[[ -n "$branch" ]] && git switch "$branch"
# Open a selected regular file
file=$(fd --type f | fzf)
[[ -n "$file" ]] && "$EDITOR" -- "$file"Customizing
# Better defaults
export FZF_DEFAULT_OPTS="--height 40% --reverse --border --info=inline"
# Use fd for the file pickers (faster than find)
export FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"Why everyone falls in love with it
You stop typing complete filenames, complete branch names, complete PIDs. Fuzzy substring + arrow-key + Enter is faster than tab completion for almost every interactive selection task.
Selection is not authorization
fzf returns text. Validate empty selections, parse stable machine-readable fields, and show the resolved target before a destructive action. Start process control with inspection and a graceful owner-aware stop, never an automatic SIGKILL.
One line is not always one value
Filenames can contain newlines, so line-oriented pipelines are not a universal path protocol. Prefer NUL-delimited producers and consumers when arbitrary filesystem names must survive selection, or constrain and validate the input set explicitly.
Separate the selector from the executor
Let fd and fzf narrow candidates, then validate the resolved value in a separate step before changing state. This keeps cancellation, parsing, and authorization visible.