Skip to main content

Output Handling

fzf outputs the selected line(s) to standard output. How you capture and use that output determines the power of fzf in your workflows.

Single Selection

# Basic capture
selected=$(ls | fzf)
echo "You chose: $selected"

# Use directly in a command (command substitution)
nvim $(find . -type f -name "*.lua" | fzf)
cat $(ls /etc | fzf)
ssh $(grep -E "^Host " ~/.ssh/config | awk '{print $2}' | fzf)
warning

If the selection contains spaces, always use quotes: nvim "$(find . | fzf)". The --print0 / --read0 flags handle filenames with newlines (rare but possible).

Multi-select Output (--multi)

With -m, each selected item is printed on its own line:

# Select multiple files, open all in vim
vim $(find . -type f | fzf -m)

# Select multiple, delete interactively
find . -name "*.bak" | fzf -m | while read -r file; do
rm -v "$file"
done

# Pipe multi-select output into xargs
find . -name "*.log" | fzf -m | xargs grep "ERROR"

Handling Spaces in Filenames

Option 1: Quote substitution

while IFS= read -r file; do
nvim "$file"
done < <(find . | fzf -m)

Option 2: Null-delimited

find . -print0 | fzf --read0 --print0 | xargs -0 cat

The --expect Flag — Capture Which Key Was Pressed

--expect lets you define alternative action keys. fzf then outputs the pressed key as the first line, your selection as the second:

# Define ctrl-v and ctrl-x as alternate keys
result=$(ls | fzf --expect=ctrl-v,ctrl-x)
key=$(head -1 <<< "$result")
file=$(tail -1 <<< "$result")

case "$key" in
ctrl-v) nvim "$file" ;; # open in vim
ctrl-x) xdg-open "$file" ;; # open with GUI app
*) cat "$file" ;; # default: print to terminal
done

This pattern lets a single fzf invocation trigger different actions.

--bind with execute vs become

Rather than capturing output and acting on it in the shell, you can trigger actions directly inside fzf using --bind:

# execute: run a command without leaving fzf
ls | fzf --bind "enter:execute(nvim {})"

# become: replace fzf process with the command (cleaner terminal)
ls | fzf --bind "enter:become(nvim {})"

# ctrl-v: open in vertical split (neovim server)
ls | fzf --bind "ctrl-v:execute(nvim -o {} &)"

The {} placeholder is replaced with the currently highlighted item.

--with-nth — Display Subset of Fields

Use --with-nth to show only some columns in fzf's list (while preserving the full line for output):

# ps aux has many columns — show only columns 1 and 11 (user and command)
ps aux | fzf --header-lines=1 --with-nth=1,11

# Show only column 2 (PID)
ps aux | fzf --with-nth=2

--nth — Search Only Specific Fields

Limit which fields fzf fuzzy-matches against:

# Only search column 2 (PID) in ps output
ps aux | fzf --nth=2

# Only search columns 2 and 3 (leave user column unsearchable)
ps aux | fzf --nth=2,3

Using --delimiter

Change the field separator for --nth and --with-nth:

# Colon-separated: search only field 1 (before first colon)
cat /etc/passwd | fzf -d: --nth=1

# Tab-separated
cat data.tsv | fzf -d$'\t' --with-nth=1,3

Output with Context: --print-query

Print the query string as the first line of output (before the selection):

result=$(ls | fzf --print-query)
query=$(head -1 <<< "$result")
selection=$(tail -1 <<< "$result")
echo "Query: $query → Selected: $selection"

Useful when the query itself is semantically meaningful (e.g., typed a hostname that isn't in the list yet).

What's Next