Replacing CLI tools with modern alternatives
25 August 2025
Over the last decade plus, I've replaced a lot of Unix CLI staples I use each day with modern alternatives, mostly written in Rust and Go. This process has been gradual over the years. I decided to take stock of where things are in 2025.
grep → ripgrep
Let's start with the big one. I use grep all the time. Unfortunately, both GNU
grep and BSD grep struggle with larger codebases and are quite fiddly to work
with. My use cases are dominated by source code, so git grep
was a step into
the right direction, but that of course only works inside Git repositories.
I first replaced grep with ack! by Andy Lester around 2008. It offered much better defaults than either of the standard tools. Searching only source code and recursively by default was already a huge step up. But speed was still an issue in larger codebases back then.
From ack! I moved on to ag, The Silver Searcher by Geoff Greer in 2011. It started as clone of ack!, but with 5-10x faster performance. Ag added support for Pthreads in 2012 and wrote an excellent post about the experience -- I wish more tools did this.
By now, Rust was gathering steam and heading for the 1.0 release. A ton of
developers were caught by the hype wave and started dabbling in systems
programming. Andrew Gallant wrote the regex
crate
for Rust, which probably inspired the birth of
ripgrep. It's even faster than any of
the previously mentioned tools, without sacrificing any of the good defaults and
ease of use. The blog post introducing
ripgrep offers a great overview of exactly how
this was achieved.
I think ripgrep is approaching the limits of how fast a grep utility can be while remaining broadly useful by default.
ls → eza
ls
is one of those commands you run hundreds of times in a day without batting
an eye. The ls
provided by GNU coreutils offers some modern allowances such as
supporting color, but once I came across exa, I
realized there was much more to ask for from a modern ls
replacement.
As is often the case with utilities like this, the original author became
unreachable over time and a fork was born. I'm actually using the actively
maintained eza
right now.
ls
is so deeply ingrained into my fingers that I could never switch to writing
exa
or eza
, so I quickly aliased ls
to eza
directly.
cd → zoxide
After ls
, it's only logical to continue with cd
. How does one even improve
on cd
, which is supposed to be quite limited in scope? By keeping a track of
which directories you've been into and matching against that history.
That is pretty much what autojump offers,
and that was my first cd
replacement. However, it is written in Python, so
when Zoxide appeared on the scene offering the same functionality it was an easy
decision to upgrade.
Just as with ls
, I'm completely unable to switch from cd
, even to the
shorter z
. Thus I've aliased cd
to z
directly.
cat → bat
When you're spelunking around in a terminal, it's often useful to take a quick
peek inside one text file or another. The cat
provided by GNU coreutils is
very plain by design, and of course there is nothing wrong with staying small
and focused -- but occasionally one wishes that for source code, we could have
stuff like line numbers and syntax highlighting right there in the terminal
output.
I assume David Peters was thinking along the same lines when he created
bat, a cat(1) clone with wings. In addition
to line numbers and syntax highlighting, it displays git
modifications and has
paging by default. All of these are nice, and if you ever need the plain output,
it's just a bat -p
away.
As with eza
and z
, I eventually aliased cat
to bat
-- otherwise I'd
often forget to use the better alternative.
find → fd
Another tool written by David Peters, fd
is a find
with better defaults and
syntax. No longer having to always write find -iname
is a small blessing.
sed → sd
sed
and awk
are incredibly powerful, but also hard to learn. The simple and
by far the most common usecase for sed
is a simple search-and-replace
operation, which is what sd
chooses to focus on. sd
supports regular
expressions rather than a messy purpose-built command language and is also
faster. sd
works really well combined with fd --exec
.
diff → delta
Delta offers syntax highlighting, word-level diff highlighting, an easy
side-by-side view and support for git blame
. All of these are improvements
over the standard diff
.
du → dust
The venerable du
from GNU coreutils suffers from poor defaults. The
--human-readable
flag always brings a smile to my face -- I guess that was an
afterthought?
dust
has great defaults and does what you'd expect a modern du
to do without
invoking any options. Now it's easy to see just how large those node_modules
and Rust's target
directories are.
hexdump → hexyl
Yet another tool written by David Peters, hexyl
is a better hexdump -C
.
That's it for the essentials. There are probably more tools out there I ought to replace with modern alternatives, and some new ones that do not replace any existing tool like fzf -- but that's a separate blog post I might write later.