Clarity trumps efficiency.
*I would've liked to write this essay to be understandable for someone without a programming/Linux background, but it was a bit too difficult. If you skip to the paragraph beginning with "...", it gets a bit easier from then on.
If you’ve ever written your own shell scripts you may have heard of the phrase “useless use of cat*”, or less tactfully, “cat abuse”. This refers to the practice, common among new shell script enthusiasts, of writing commands like “cat file.txt | grep name”, when “grep name file.txt” would serve perfectly well. Tools like shellcheck will bug you about it—along with similar constructions like “ps ax | grep Discord | wc -l” instead of “pgrep -c Discord”.
Well, I’m here to defend cat abuse! There are two arguments I see against the cat | grep construction, one of which is valid but situational, and the other of which is completely invalid. The former is that the extra pipe just adds additional overhead into the command. Yes, it does. And it’s unlikely to matter at all if you’re using it on 20KiB text files on a system built in the past 40 years; however, in production, when writing tools that need to be able to deal with arbitrarily large text files as efficiently as possible, sure.
The latter is “well, it’s just unnecessary”. I disagree. I think the cat | grep construction—along with similar such as grep | wc, ps | grep, ps | awk, and so on—serves a very important purpose in that it makes shell scripts easier to read, easier to modify, and easier to debug.
Consider this example from above:
ps ax | grep Discord | wc -l
Read the process table; filter for "Discord"; count the number of lines. It’s very atomic. Each operation can be swapped out for something else without confusing the reader. On the other hand:
pgrep -c Discord
Now, this does the same thing—counting the number of lines in the process table with "Discord" in them. It looks like only one operation... but it’s really still three in disguise. And worse, imagine you suddenly want to add another filter; sorting not only by Discord, but by processes that include the word “title”. This is not straightforward at all! It turns out that while regex has a standard way of searching for alternatives, it really does not provide an easy method for searching for BOTH of two words. On the other hand, with the atomic version, it’s easy:
ps ax | grep Discord | grep title | wc -l
Take that, “useless” use of cat.
There’s a broader meaning, though, to my statement of “clarity trumps efficiency”. I apply it to every aspect of use of electronics, from web searches to backup routines to yes, silly little shell scripts that use cat.
I use command aliases, but to a pretty limited degree; I avoid cutesy stuff like “ll” for “ls -l” and “yeet” for “pacman -Rns”, along with possibly-dangerous substitutions like “rm” for “rm -i”; I’d never dream of aliasing “nano” or “vi” to my preferred text editor (vim). I believe strongly that my commands should be transparent, and saving me from my own muscle memory once or twice is not worth making them completely opaque.
Tab completion on the other hand is one of my favorite features in the shell. It’s the perfect combination of transparent and convenient; without having to alias any of my application names or get hit by the information overload fuzzy finding gives you, I can still launch any of them in no more than four keystrokes. (Except audacious and audacity, admittedly.)
I use a floating window manager (Openbox), and when I need to briefly use a tiling layout, I have a very boring way of doing so: focusing each window one by one and moving it into the slot I want. (While holding down the Super/Windows key, 1-C-2-V does a basic left-right split.)
... I make some use of spellcheck on assignments to be turned in, but never autocorrect, which I abhor even in messaging apps. Every change to your inputs should be deliberate; otherwise you’ll never learn what you’re doing wrong, and you’ll never need to be precise because you’ve turned over that part of your brain to the algorithm.
This leads me to an important corollary of my principle: “it’s better to have a slow algorithm that you understand, than a fast one that you don’t”.
Satya Nadella’s vision of the PC of the future is one where you tell it what to do in natural language and it interprets that using LLMs and so on into machine instructions. Instead of viewing a PC as a toolbox you go into the workshop with, and work on projects with in certain defined ways, he wants the PC to be an assistant; you give the assistant directions and pray that it gets things right. Of course you aren’t allowed into the workshop with the tools anymore; that’s the assistant’s job!
Anyone who’s used Google Search over the past ten years knows how miserable this model is; you search for a specific phrase that Google “helpfully” corrects to something it thinks you meant. There was a learning curve to the old way, but once you learned how to state queries precisely, you were done; now you need to play psychologist, sociologist, and statistician all at once.
This is a decent part of why I dislike generative AI, though far from the main reason. I don’t want an opaque algorithm making decisions for me, unless those decisions are incredibly low-level stuff like core parking that no human should be directly involved with in the first place.
To get back to my own setup, I have a whole text file documenting the system maintenance process I go through once every month; most of it could be automated, but I make every step a deliberate choice. Not to go all new-age, but for me specifically—it all ties back in to mindfulness.
I think people have only a vague concept of what mindfulness is. Until two years ago or so, I was the same way. But to who I am now, mindfulness means not doing anything on autopilot. Instead of letting yourself half-doze off on a drive home, scarcely remembering the 20 minutes from the parking lot to the garage, be conscious of every turn. Instead of immediately putting on music and blocking out the world on a train ride to the next city, force yourself to be present in the train car, and notice the way the light reflects on the plastic seat two rows in front.
And to me, clarity in code, and in UX, is a part of this mindfulness. Programs that are easy to read, easy to modify, and easy to debug encourage you to look closer—to consider every atom that goes into their statements instead of taking them for granted. Slow algorithms that you understand can help you think of improvements; fast algorithms that you don’t encourage you to give up and leave the real thinking to someone else.
So write silly little shell scripts with five pipes in a single statement, and yes, that uselessly use cat. Rather than doing anything wrong—you’re allowing yourself and others to think, to try, and to improve.















