Skip to content

The Modern CLI Starter Pack: Seven Replacements for the Unix Classics

ls and grep have been on the job since the early 1970s, and it shows — not in reliability, which is beyond reproach, but in defaults designed for teletypes and terminals eighty columns wide. Over the last decade a small army of rewrites has asked a fair question: what if the classics had colours, respected your .gitignore, and didn’t require a man page for basic use?

Here are the seven replacements actually worth your muscle memory. All free, all open source, all single self-contained binaries, and — with one exception — written in Rust, because of course they are.

Instead of Try What you get
ls eza Colours, icons, git status, tree view
cat bat Syntax highlighting, line numbers, git markers
grep ripgrep Speed, and it skips everything you ignore
find fd A syntax a human can remember
cd zoxide Jump to directories by name fragment
git diff pager delta Diffs you can actually read
(everything) fzf Fuzzy-find files, history, anything

Replaces: ls

exa was the original “modern ls” until development stalled; eza is the community fork that carried on, because no Rust binary is ever truly allowed to die. It does what ls does, then keeps going: colours that mean something, icons, a per-file git status column, and a tree view for when you want the shape of a directory rather than its contents.

Terminal window
eza -l --git --icons
eza --tree --level=2

Install: brew install eza · sudo dnf install eza · sudo apt install eza on recent Ubuntu and Debian (older LTS releases: prebuilt binaries on GitHub).

Catch: your distro’s LTS repos may not have it yet, and the icons need a Nerd Font in your terminal — the same one your Starship prompt already wants.

Replaces: cat

“A cat clone with wings”, by its own description, and who are we to argue. bat adds syntax highlighting for a couple of hundred languages, line numbers, git change markers in the gutter, and automatic paging for long files.

Terminal window
bat src/main.rs

The detail that makes it alias-safe: when its output is piped, bat drops the decorations and behaves exactly like cat, so cat file | something keeps working even if cat is bat.

Install: brew install bat · sudo apt install bat · sudo dnf install bat.

Catch: Debian and Ubuntu call the binary batcat (a package name clash, long story). One alias fixes it: alias bat=batcat.

Replaces: grep

ripgrep (rg) searches recursively by default, respects your .gitignore, skips hidden files and binaries, searches in parallel, and is fast enough that your reading speed becomes the bottleneck. It began life as a showpiece for Rust’s regex engine and ended up in everyone’s toolbox by being simply, embarrassingly better.

Terminal window
rg "TODO" # everywhere, respecting .gitignore
rg "fn main" -t rust # Rust files only
rg "secret" -uu # include hidden and ignored files

Install: brew install ripgrep · sudo apt install ripgrep · sudo dnf install ripgrep.

Catch: it is not POSIX grep — the flags differ (recursion is the default; there is no -r). You’ll still want real grep in your fingers for other people’s servers.

Replaces: find

find is powerful in the way a tax code is powerful, and its syntax was clearly designed by someone who has never met a human. fd keeps the power and bins the incantation: the pattern is a regex, the search starts at the current directory, and .gitignore is respected here too.

Terminal window
fd readme # anything matching "readme", below here
fd -e md # by extension
fd -x wc -l # run a command on every result

Compare find . -iname "*readme*", which you had to look up just now. Again.

Install: brew install fd · sudo apt install fd-find · sudo dnf install fd-find.

Catch: Debian and Ubuntu strike again — the binary there is fdfind. Same alias trick applies.

Replaces: cd (mostly)

zoxide watches which directories you visit, then lets you jump to them by fragment: z doc takes you to your most “frecent” — frequent plus recent, a portmanteau only a tool this useful gets away with — match. zi opens an interactive picker powered by fzf. After a week it knows your habits better than you do.

It needs one line in your shell config to hook in:

~/.zshrc
eval "$(zoxide init zsh)"

Install: brew install zoxide · sudo apt install zoxide · sudo dnf install zoxide.

Catch: it only knows where you’ve been since installation, so the first few days feel unremarkable. Persist. Plain cd keeps working alongside it, and if you’re fully converted, zoxide init --cmd cd zsh will take over the cd command itself.

Replaces: nothing, and half of everything

fzf is less a tool than a universal solvent for lists: pipe any list into it and you get a fuzzy, type-to-filter picker. Its shell integration is where it earns the spot here — Ctrl+R becomes a full-screen fuzzy history search, Ctrl+T inserts a fuzzy-picked file path into your command line, and Alt+C fuzzy-changes directory.

Terminal window
# ~/.zshrc — shell integration (fzf 0.48 and later)
eval "$(fzf --zsh)"
Terminal window
vim $(fzf) # the party trick that sells it

If Ctrl+R was the one shortcut you took from our keyboard shortcuts cheat sheet, this is that keystroke graduating from party trick to superpower. The one exception to the Rust theme, incidentally — fzf is Go.

Install: brew install fzf · sudo apt install fzf · sudo dnf install fzf.

Catch: the fzf --zsh integration flag needs version 0.48 or newer; older distro packages ship a key-bindings.zsh file to source instead. Check with fzf --version.

Replaces: git’s default pager

git diff output has historically been formatted for computers that enjoy punishment. delta gives it syntax highlighting, line numbers, and n / N to jump between changed files, with optional side-by-side view for wide terminals. It’s a pager, not a replacement for git itself — configure once and every git diff, git show and git log -p improves silently.

~/.gitconfig
[core]
pager = delta
[interactive]
diffFilter = delta --color-only
[delta]
navigate = true
[merge]
conflictstyle = zdiff3

Add side-by-side = true under [delta] if your terminal has the width for it.

Install: brew install git-delta · sudo dnf install git-delta · elsewhere, binaries on GitHub.

Catch: if you already do all your diffing in a GUI tool, this changes nothing about your life. For everyone else it’s the highest ratio of effort to improvement on this page.

Partly. Aliases only apply to interactive shells — scripts never see them, so nothing breaks there — and both bat and eza detect pipes and behave themselves. These are safe:

~/.zshrc
alias ls='eza --icons'
alias ll='eza -l --git --icons'
alias cat='bat'

But don’t alias grep to rg or find to fd: the flags differ, and one day you’ll paste a command expecting POSIX behaviour and get a confusing error instead. Type the new names until they stick. And keep the classics in your repertoire regardless — these tools make your machines nicer; they don’t excuse you from knowing grep on somebody else’s.

  • dustdu with a bar chart and a sense of proportion
  • dufdf, but readable
  • btoptop/htop with an interface that belongs in a film about hacking
  • sdsed without the regex dialect archaeology
  • hyperfine — benchmarks commands properly, with warmup runs and statistics
  • tldr — man pages, but just the three examples you actually wanted
  • jq — not a replacement for anything; simply the correct answer to JSON on the command line

That’s the toolbox modernised. For the rest of the setup: a prompt that earns its keep, the keyboard shortcuts worth memorisingCtrl+R included, now with fuzz — and tmux to keep the whole lot alive when the Wi-Fi refuses to.