The fuzzy finder that changed how I use the terminal
I spend a lot of time in the terminal. File navigation, searching through history, switching git branches—all of it involves typing. A lot of typing. Then I discovered fzf, and everything changed.
fzf is a command-line fuzzy finder written in Go. You type a few characters, and it instantly filters through thousands of lines to find what you need. It’s fast. Really fast. And it integrates with practically everything—bash, zsh, fish, vim, neovim, tmux.
What Makes fzf Special
The core idea is simple: pipe any list into fzf, and it becomes searchable. Files, command history, git branches, processes, environment variables—anything.
Here’s the basic pattern:
# Find a file and open it in vim
vim $(fzf)
# Search command history interactively
history | fzf
# Kill a process by searching for it
kill -9 $(ps aux | fzf | awk '{print $2}')
But the real magic is how it handles matching. Type “src” and it finds “source”. Type “mncfg” and it matches “main_config.go”. The algorithm is smart about what you probably mean.
Why Go Was the Right Choice
fzf processes thousands of items in milliseconds. This isn’t accidental. Go’s concurrency model makes it easy to parallelize the matching algorithm. The single binary distribution also means no runtime dependencies—just download and run.
If you’ve read about Go’s context package, you know Go handles cancellation well. fzf uses this to stop searching the moment you refine your query. No wasted cycles.
Here’s a simplified example of how you might implement fuzzy matching in Go:
package main
import (
"fmt"
"strings"
)
func fuzzyMatch(pattern, text string) bool {
pattern = strings.ToLower(pattern)
text = strings.ToLower(text)
pIdx := 0
for _, char := range text {
if pIdx < len(pattern) && byte(char) == pattern[pIdx] {
pIdx++
}
}
return pIdx == len(pattern)
}
func main() {
items := []string{"main.go", "main_test.go", "config.yaml", "README.md"}
pattern := "mgo"
for _, item := range items {
if fuzzyMatch(pattern, item) {
fmt.Println(item) // Prints: main.go, main_test.go
}
}
}
The actual fzf implementation is far more sophisticated. It uses a scoring system to rank matches and leverages goroutines for parallel processing.
Shell Integration That Just Works
The killer feature is shell integration. After installing, fzf hooks into your shell to supercharge common operations.
For zsh users:
# Add to your .zshrc
source <(fzf --zsh)
For bash:
# Add to your .bashrc
eval "$(fzf --bash)"
For fish shell users, it’s similar. Once enabled, you get:
CTRL-T: Fuzzy find files and paste the pathCTRL-R: Search through command historyALT-C: Fuzzy cd into directories
I use CTRL-R constantly. Instead of pressing up arrow fifty times, I type a few characters from any command I’ve ever run.
Integrating fzf with Your Go Workflow
Here’s a practical script that combines fzf with common Go tasks:
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
// Find all Go test files
cmd := exec.Command("find", ".", "-name", "*_test.go")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Run()
// Pipe to fzf
fzf := exec.Command("fzf", "--preview", "head -50 {}")
fzf.Stdin = strings.NewReader(out.String())
fzf.Stderr = os.Stderr
var selected bytes.Buffer
fzf.Stdout = &selected
if err := fzf.Run(); err != nil {
os.Exit(1)
}
file := strings.TrimSpace(selected.String())
fmt.Printf("Running tests in: %s\n", file)
// Run tests for selected file
test := exec.Command("go", "test", "-v", "-run", ".", file)
test.Stdout = os.Stdout
test.Stderr = os.Stderr
test.Run()
}
This lets you interactively select which test file to run. The --preview flag shows a preview of each file as you navigate.
tmux and vim Integration
If you use tmux, fzf can help you switch sessions and windows interactively. If you use vim or neovim, plugins like fzf.vim bring fuzzy finding directly into your editor.
The unix philosophy of composable tools shines here. fzf doesn’t try to do everything. It does one thing exceptionally well and plays nice with other tools.
Try It Today
Install fzf and spend ten minutes with it. Run fzf in a directory with lots of files. Try CTRL-R for history search. You’ll wonder how you lived without it.
The source code is worth reading too. It’s clean, well-documented Go that demonstrates how to build fast CLI tools. Check out the GitHub repository to see how it’s structured.