Aku Kotkavuo

@eagleflo

Portrait

I am a software generalist from Helsinki, Finland. I’ve been working with software for most of my life. I practise writing about related topics here.

My open source projects include mpyq and jisho.


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.