You know the drill. A config value is hiding in a codebase of tens of thousands of lines. You reach for grep -r, stare at a wall of matching lines, then pipe it through find and sed to make sense of it. There is a faster way, and it is a stack of three open source tools that fit together: ripgrep for searching, fzf for interactive selection, and bat for readable output. All three are small, fast, and installed in seconds on Linux and macOS.
This is a hands-on review. Every command below I ran against a real codebase, so you can copy them and expect the same output shape.
Prerequisites
- Linux or macOS with a package manager
- A codebase or folder with a few thousand files to search against
grepandfindinstalled (you already have them)
Install the three tools
Install each with your package manager.
# Debian/Ubuntu
sudo apt install ripgrep fzf bat
# macOS (Homebrew)
brew install ripgrep fzf bat
Debian names the bat binary batcat to avoid a clash with an older package. If the bat command is missing on your distro, use batcat or add an alias.
ripgrep: searching that keeps up
ripgrep is a grep replacement written in Rust. It respects .gitignore by default, so it skips node_modules, build output, and vendored code unless you tell it otherwise. That is the reason searches feel instant.
Search a folder, showing line numbers:
rg "TODO" src
Search only config file types:
rg --type json "name" .
List every file of a given type, the way find does but faster and honoring ignores:
rg --files -g '*.ts' src
Match files by filename glob:
rg "portfolio" -g '*.toml' .
Count matches per file, useful for spotting where a term clusters:
rg -c "astro" src
Answers two practical questions every day: where is this string, and what files match this pattern. The output is colorized by default and file names are written so that the next tool can swallow them.
fzf: turning matches into choices
fzf is a fuzzy finder. You type a few characters and every partial match ranks by relevance, with the best result highlighted. It is interactive, so it takes over the terminal while you filter.
Use it on its own to pick a file quickly:
fzf
The powerful part is composition. Feed fzf a stream of file names from ripgrep, pick one, and run a command on it:
vim "$(rg --files | fzf)"
That is one habit that replaces most of your tab-through-directories time. The pipeline is: list files fast, fuzzy-filter fast, act.
bat: output that reads itself
bat is cat with syntax highlighting, line numbers, and a git gutter. Point it at any file:
bat src/data/articles.ts
It also reads standard input, which is what makes it pair so well in a pipeline. Sequence the whole arm: search for a term, fuzzy-pick a file, then open that file pretty-printed at the matching line.
rg --line-number "TODO" "$(rg --files | fzf)" | bat
Verdict
| Tool | Does | Best at | Watch out for |
|---|---|---|---|
| ripgrep | fast content + filename search | searching gigabytes in milliseconds, respects .gitignore | customize types via rg --add-type when your extension is unknown |
| fzf | interactive fuzzy selection | choosing from a long list fast, composing with any command | interactive, so it needs a terminal |
| bat | pretty printing files and stdin | reading code with syntax highlighting and line numbers | Debian may name it batcat |
The three are strongest together. ripgrep does the heavy lifting, fzf lets you choose, bat makes the result readable. None of them replaces the others, and all three install in one line.
When to use these vs alternatives
grep/find: keep calling them when you need POSIX behavior on a machine where you cannot install anything. Once ripgrep and fzf are present, you will reach for them rarely.ack/ag: ripgrep is generally faster and ships in more package managers; if you already know ack or ag you will learn ripgrep in minutes because the flags overlap.- IDE search (Ctrl+Shift+F): use the IDE intellisense when you need results tied to the project tree and integrated refactoring. Use the terminal stack when you want to search files outside the workspace or script the result.
- Spotlight / app launchers: fuzzy pickers also exist as GUI tools (like Raycast, Alfred, or uLauncher). fzf does the same job inside the shell, which matters if you live in the terminal.
fd: a fasterfindthat pairs with fzf and bat. Iffindis your bottleneck, addfd; ripgrep already covers most filename needs with--files.
Next steps
Wire fzf into your shell history and let it run a command on its own output.
# fuzzy-search your shell history
history | fzf
Read the man pages when a flag does not behave as expected: man rg, man fzf. Both document the type system and key bindings in depth. If you script a lot of searches, look at rg --files --json and fzf --preview, which lets you show file contents in a side pane while you filter.