Fuzzy and Exact Search Syntax
fzf supports multiple matching modes within a single query. You can mix fuzzy terms, exact strings, anchors, and negations in one search expression.
Core Idea
fzf queries are space-separated tokens. Each token is matched independently, and all tokens must match for a result to appear (AND logic). Use | for OR between tokens.
Token Types
| Token | Syntax | Matches |
|---|---|---|
| Fuzzy | word | Fuzzy match — chars in order, not necessarily adjacent |
| Exact | 'word | Exact substring match (apostrophe prefix) |
| Prefix exact | ^word | Line must start with word |
| Suffix exact | word$ | Line must end with word |
| Exact full-line | ^word$ | Line equals word exactly |
| Negation fuzzy | !word | Must NOT fuzzy-match word |
| Negation exact | !'word | Must NOT contain word |
| OR operator | `tok1 | tok2` |
Fuzzy Matching
# Query: "nvconf"
# Matches: ~/.config/nvim/lua/config/options.lua ← all chars present in order
# Matches: /etc/nginx/nginx.conf ← n, v, c, o, n, f all present
# Scores higher when chars are consecutive and near start of words
ls ~/.config | fzf
# Type: nvim → matches "nvim" directory
# Type: nvco → matches "nvim/lua/config/options.lua"
Exact Match (')
Prefix your term with ' (single apostrophe) for an exact substring match:
# Only lines that literally contain "nginx.conf"
ls /etc -R | fzf --query "'nginx.conf"
# Exact "error" (case insensitive by default)
cat /var/log/syslog | fzf --query "'error"
Anchored Matching
# Lines starting with "server"
cat /etc/nginx/nginx.conf | fzf --query "^server"
# Lines ending with ".conf"
ls /etc | fzf --query ".conf$"
# Lines that are exactly "nginx"
ls /etc | fzf --query "^nginx$"
# Prefix fuzzy: line starts with n, v, i, m in order
ls | fzf --query "^nvim"
Negation
Prefix with ! to exclude matches:
# Show everything EXCEPT files containing "backup"
ls | fzf --query "!backup"
# Exact negation: exclude lines containing ".log"
ls | fzf --query "!'\.log"
# Exclude lines starting with "."
ls -a | fzf --query "!^."
AND Logic (Multiple Tokens)
Tokens separated by spaces are ALL required to match (AND):
# Must match "nginx" AND ".conf"
ls /etc -R | fzf --query "nginx .conf"
# Must match both "error" AND "2024"
cat /var/log/syslog | fzf --query "error 2024"
# Must match "server" AND NOT "upstream"
cat nginx.conf | fzf --query "server !upstream"
OR Logic (|)
Use | (pipe, with spaces) for OR between terms:
# Lines matching "python" OR "ruby"
ls /usr/bin | fzf --query "python | ruby"
# Exact "nginx.conf" OR exact "apache.conf"
ls /etc -R | fzf --query "'nginx.conf | 'apache.conf"
Case Sensitivity
By default, fzf is case-insensitive. Behavior changes when the query contains uppercase:
# Case insensitive (no uppercase in query)
ls | fzf --query "nginx" # matches Nginx, NGINX, nginx
# Case sensitive (uppercase present)
ls | fzf --query "Nginx" # matches only Nginx (not nginx)
Force case behavior with flags:
fzf -i # always case-insensitive
fzf +i # always case-sensitive
fzf --smart-case # default: smart (mixed case = case-sensitive)
Regex Matching (--algo)
fzf's default algorithmis fuzzy (v2). For exact regex on the query:
# Regex mode via filter flag
ls | fzf --filter "^[0-9]" # non-interactive: lines starting with digit
# Note: fzf doesn't support full regex interactively by default
# Use rg or awk to pre-filter, then pipe to fzf
ls /var/log | grep -E "\.log$" | fzf
Practical Search Examples
# Find all Python files except test files
find . -name "*.py" | fzf --query "!test"
# Find nginx configs but not backups
ls /etc/nginx -R | fzf --query "^sites .conf$ !backup"
# Find error log lines from today
cat /var/log/syslog | fzf --query "'$(date +%b\ %d) error"
# Find docker images with "python" or "node" tags
docker images | fzf --query "python | node !none"