The core Unix tools were designed in the 1970s for teletypes and kilobytes of RAM. They still work — but a generation of rewrites (mostly in Rust, a few in Go) has quietly fixed their worst UX problems: cryptic flags, no awareness of .gitignore, and output that assumes you enjoy parsing monochrome walls of text.
Here are the 8 replacements I actually use daily, with the exact commands that made me switch.
1. ripgrep (rg) — replaces grep
ripgrep searches recursively by default, respects your .gitignore, skips binary files, and is genuinely 5–50x faster than GNU grep on real codebases. The flags you'll actually use:
rg "handleWebhook" # search everywhere, respects .gitignore
rg -i "error" # case insensitive
rg -S "UserID" # smart case: insensitive unless you type a capital
rg -l "TODO" # just list files with matches
rg -C 3 "panic" # 3 lines of context around each hit
rg --files -g "*.py" # list all Python files it would search
The killer detail: rg "foo" in a repo already excludes node_modules, target/, and whatever else you've gitignored. With grep you've been typing --exclude-dir chains for years. That alone is worth the switch.
2. fd — replaces find
Nobody should have to remember find . -name "*.log" -mtime +30 -exec rm {} \;. fd's syntax is what find's should have been:
fd report # find files/dirs matching "report" (regex, recursive)
fd -e log # by extension
fd -t d node_modules # directories only
fd -x rm # run rm on every match
fd changed -d 3 # match "changed", max depth 3
Like ripgrep, it respects .gitignore and is dramatically faster on large trees. One gotcha: on Debian/Ubuntu the package is fd-find and the binary is fdfind — alias it in your shell rc: alias fd=fdfind.
3. bat — replaces cat
bat adds syntax highlighting, line numbers, and a Git gutter (showing modified lines) to file viewing:
bat src/main.go # highlighted, numbered, paged
bat --plain deploy.sh # plain output, safe for piping
bat -r 40:60 app.py # show only lines 40-60
It pages through less automatically when output is long, and passes through cleanly when piped — so aliasing alias cat=bat is safe for interactive use (keep real cat in scripts).
4. eza — replaces ls
exa was the popular modern ls, but the project went unmaintained and its repo was archived. eza is the actively maintained community fork — install that one, not exa.
eza -l --git --icons # long view with git status per file
eza --tree -L 2 # tree view, 2 levels deep
eza -l --sort=modified # sort by modification time
The --git column showing staged/modified status next to each filename is the feature that makes plain ls -la feel broken afterward.
5. zoxide — replaces cd
zoxide learns which directories you visit and lets you jump with fragments instead of paths. After a day of use:
z auto # jumps to /tmp/auto-blog (your most "frecent" match)
z blog docs # matches paths containing both
zi # interactive picker (uses fzf)
Setup is one line in your .zshrc or .bashrc:
eval "$(zoxide init zsh)"
"Frecent" = frequency + recency. The directory you edited ten minutes ago outranks one you visited heavily last month. It sounds like a gimmick until you realize you've stopped typing full paths entirely.
6. fzf — fuzzy-finds everything
fzf isn't a replacement for one tool — it's an interactive filter you wire into your whole shell. The three bindings that change your life (installed via the package's install script):
Ctrl-R— fuzzy-search your shell history. Type a fragment of a command you ran last week, hit enter. This alone ends thehistory | grepera.Ctrl-T— fuzzy-find files and paste the path into your current command line.Alt-C— fuzzy-jump into a subdirectory.
And the composition pattern is endless:
vim $(fzf) # pick a file, open it
git checkout $(git branch | fzf) # pick a branch, check it out
kill $(ps aux | fzf | awk '{print $2}')
Unlike most of this list, fzf is written in Go (by Junegunn Choi) — proof the ecosystem isn't a monoculture.
7. jq — JSON without tears
Every API, CI system, and cloud CLI speaks JSON. jq is how you answer questions without writing a Python script:
curl -s api.example.com/users | jq '.users[].email'
kubectl get pods -o json | jq '.items[] | select(.status.phase=="Failed") | .metadata.name'
jq -r '.dependencies | keys[]' package.json # raw output, no quotes
Learning curve tip: master just three things — .key, .[], and select(). That covers 90% of daily use. The -r (raw) flag matters more than people expect; without it you're sed-ing quotes off strings forever.
8. delta — replaces git's default diff pager
delta renders git diff and git show with syntax highlighting, line numbers, and optional side-by-side view. Configure once in ~/.gitconfig:
[core]
pager = delta
[interactive]
diffFilter = delta --color-only
[delta]
line-numbers = true
side-by-side = true
Every diff you read from then on — including inside git add -p — is highlighted and numbered. Code review in the terminal stops being eye strain.
Install everything in one line
# macOS
brew install ripgrep fd bat eza zoxide fzf jq git-delta
# Debian/Ubuntu (note the renamed binaries)
sudo apt install ripgrep fd-find bat jq fzf
# eza, zoxide and delta: use cargo install, or their .deb releases
Bottom Line
Don't install all eight at once — you'll remember none of them. Start with ripgrep and fzf's Ctrl-R; they'll pay rent within an hour. Add zoxide next week. By the time you wire in delta, the 1970s toolchain will feel like a museum exhibit.
The pattern behind all of these isn't speed — it's defaults. They assume you're in a Git repo, on a color terminal, in 2026. The classics assume a teletype. Pick accordingly.