cli

fzf - The Command-Line Fuzzy Finder

How fzf, the command-line fuzzy finder, works, and practical ways to use it for file search, command history, and more.

I use the command line a lot at my day job, and I lean on a handful of tools to keep the workflow fast. This is the first post in a biweekly series where I cover one of those tools at a time. First up: fzf, the command-line fuzzy finder, and how it can speed up your day-to-day work.

fzf skips exact matching: you type a rough guess and it finds the closest match in files, history, or branches.

What fzf is and why use it

Before getting into fzf itself, it’s worth covering what fuzzy matching is and the algorithms behind it.

What fuzzy matching is

Fuzzy matching is a technique for finding strings that are approximately equal, or closely resemble each other. Unlike exact matching, which looks for an exact match, fuzzy matching identifies matches that may not be perfect but are “close enough” against a set of criteria.

It’s used a lot in data cleaning, where it helps identify duplicate records in large databases even when entries aren’t exactly the same (for example, “McDonald’s” vs. “Mc Donalds”).

It’s also useful in search engines and autocorrect, where a typo or slight variation in a search term can still return the result you wanted.

How it works, in the simplest terms

Fuzzy matching algorithms score strings based on metrics such as the number of changes needed to turn one string into another (edit distance), or the number of shared character sequences. The result is usually a score, and a higher score means greater similarity.

Algorithms used in fuzzy matching

  1. Edit distance (Levenshtein distance): This measures the similarity between two strings by finding the minimum number of single-character edits (insertions, deletions, or substitutions) needed to turn one string into the other. For example, the Levenshtein distance between “kitten” and “sitting” is 3.

  2. Damerau-Levenshtein distance: An extension of Levenshtein distance that also accounts for transpositions (swapping two adjacent characters). For instance, the distance between “flaw” and “lawn” is 1 with Damerau-Levenshtein.

  3. Smith-Waterman algorithm: Originally built for bioinformatics, this local sequence alignment algorithm also works for text comparisons. It’s especially good at scoring the similarity of substrings.

  4. Jaro and Jaro-Winkler distance: Measures of similarity between two strings. Jaro-Winkler gives more weight to the prefix of the strings, which makes it useful for short strings like names.

  5. n-gram analysis: Strings get broken into overlapping substrings of “n” characters, and those n-grams get compared to find similarities. For example, using 2-grams (bigrams), the word “hello” breaks down into [“he”, “el”, “ll”, “lo”].

  6. Token-based matching: Breaks strings into tokens (usually words) and compares those tokens for similarity, using techniques like cosine similarity or Jaccard similarity.

  7. Tf-idf (term frequency-inverse document frequency): More common in information retrieval, but it applies to fuzzy matching too. It measures how important a word is to a document relative to a collection of documents, and can pair with cosine similarity for document comparisons.

  8. Longest common subsequence (LCS): Finds the longest sequence of characters that two strings share. The LCS of “ABCBDAB” and “BDCAB” is “BCAB”.

Different use cases call for different algorithms, or combinations of them. It depends on the tradeoff between speed and accuracy, the nature of the data, and the context you’re matching in.

So what is fzf, and why use it

fzf is a flexible tool that lets you search and navigate any list (files, command history, git branches, and so on) using fuzzy matching. You don’t need to type exact search terms: you can make typos or give partial input, and fzf will suggest matches.

For instance, if you have files named “important_document”, “imported_files”, and “impromptu_notes”, typing “imp doc” in fzf might highlight “important_document” as the top match even though the search isn’t an exact substring.

fzf is fast: it searches files and command history in real time as you type, with an interface that stays out of your way. It also integrates with plenty of other tools, including Vim.

Setting up and using fzf

Follow the fzf installation instructions for your OS. On macOS, install it with brew install fzf, then run /opt/homebrew/opt/fzf/install to set up the shell completions.

fzf usage

Here’s the basic usage of fzf:

  1. File Search
bash
fzf
  1. Command History Search
bash
Press CTRL + R in your terminal to interactively search through your command history.
  1. Preview Window
bash
$ find dir/ | fzf --preview 'cat {}'
  1. Using fzf with Other Commands
bash
$ ls -l $(fzf)  # List the details of a selected file
  1. Select and Kill Processes
bash
$ kill -9 $(ps aux | fzf | awk '{print $2}')
  1. Filter Git Branches
bash
$ git branch | fzf
  1. Searching through your browser history (Firefox)

You can also use fzf to search your browser history. The SQLite database that stores it is typically at this path on a Mac:

~/Library/Application Support/Firefox/Profiles/*.default-release.

Navigate to that directory, then run:

bash
sqlite3 places.sqlite "SELECT url FROM moz_places" | fzf

This covers the basics, but fzf has a lot more to explore. If you have tips of your own, or ways you use fzf that aren’t here, share them in the comments.



If you liked this post, you can support my work by buying me a coffee. It would mean a lot. If you share this on Twitter, tag me @muhammad_o7.

Want new posts in your inbox? Subscribe by email or follow the RSS feed.