The terminal habits I finally broke
I spent years defending a slow terminal setup because switching felt like overhead I didn't have time for. Then a coworker watched me grep through a monorepo for twenty seconds, run a Python one-liner to pretty-print a JSON response, and scroll through man curl looking for a flag I use maybe once a month — and asked, not unkindly, why I was doing all of that by hand. These seven tools are the ones that actually stuck, in the order I'd install them again on a new machine. Each one replaces something I was already doing, just slower.
ripgrep, because grep makes you remember its own defaults
ripgrep (the rg command) searches file contents recursively, skips your .gitignored files and node_modules automatically, and is fast enough that I stopped thinking about scoping searches to a subdirectory first.
rg "TODO: fix before launch" --type php
rg -l "deprecated_helper\(" | xargs -I{} echo "check: {}"
The default grep -r equivalent means either remembering --exclude-dir=node_modules --exclude-dir=.git every time or accepting a search that chokes on a vendor directory for ten seconds before returning results buried in noise. ripgrep gets the gitignore-awareness right out of the box, which sounds small until you've searched the same repo a hundred times.
fzf, for when you know roughly what you're looking for
fzf is a fuzzy finder that pipes into anything. I use it constantly for two things: jumping into a recent directory and searching shell history without the arrow-key-and-hope method.
# fuzzy search command history (bound to Ctrl+R with fzf's shell integration)
history | fzf
# fuzzy-find a file and open it in the editor
vim $(fd --type f | fzf)
The default alternative — pressing Ctrl+R in bash and typing a guess at the exact substring you used last time — works fine until your history has three similar commands from different days. fzf shows all of them ranked by match quality and lets you scroll, which turns a guessing game into a two-second lookup.
jq, because API responses are not meant to be read raw
Any time I'm hitting an API from the terminal, the response comes back as a single unformatted line of JSON. jq formats it, and more importantly, lets me pull out exactly the field I care about without eyeballing a wall of text.
curl -s https://api.example.com/bookings | jq '.data[] | {id, status, customer: .customer.email}'
Before jq, my workflow was piping into python -m json.tool for formatting and then still scanning the whole thing by eye for the field I needed. jq does both steps in one pass, and the filter syntax, once it clicks, is faster to write than it looks.
httpie, for requests you don't want to open Postman for
Postman is the right tool for a structured collection with saved environments and test scripts — I cover that setup in A Real Workflow With Postman — but for a single quick check against an endpoint, opening a GUI app is slower than typing a command.
http POST api.example.com/bookings customer_id=42 slot=2026-08-20T10:00 \
Authorization:"Bearer $TOKEN"
httpie's syntax reads closer to plain English than curl's, and it pretty-prints and syntax-highlights the response by default, which curl doesn't do without extra flags piped into something else. If I need to inspect the IP or hosting provider behind an unfamiliar host that shows up in a log file, I still switch over to a proper IP lookup tool rather than trying to reconstruct that from whois output in a terminal — some lookups are genuinely faster in a browser.
bat, for reading code without leaving the terminal
bat is cat with syntax highlighting, line numbers, and Git-aware markers showing which lines changed against the index.
bat app/Http/Controllers/BookingController.php
The plain cat alternative dumps a wall of unhighlighted text, which is fine for piping into another command but genuinely harder to read when you're just trying to check what a file contains before deciding whether to open it in the editor at all.
entr, for rerunning a command when files change
entr watches a list of files and reruns a command whenever one of them changes. I use it for anything that doesn't already have its own watch mode — running a specific test file, regenerating a docs build, linting a single directory.
fd --extension php app/Services | entr -c php artisan test --filter=BookingServiceTest
The alternative is alt-tabbing back to the terminal and pressing the up arrow after every save, which doesn't sound slow until you count how many times a day you actually do it. entr turns that into zero extra keystrokes per save.
tldr, because man pages are written for reference, not recall
man pages are complete and exhaustive and exactly the wrong format when you just need to remember the one flag you use for tar. tldr pages are community-maintained, example-first cheat sheets for the same commands.
tldr tar
tldr rsync
Instead of scrolling past a page of option descriptions, tldr shows five or six copy-pasteable examples of the command doing common things. I still open the real man page maybe once a month for something obscure, but tldr covers the other ninety percent of lookups faster.
Tools I tried and didn't keep
Worth naming a couple that didn't make the cut, because the reasons matter as much as the recommendations. exa (a replacement for ls with colors and git status built in) looked great in every demo I watched and lasted about two weeks on my actual machine before I quietly went back to plain ls with a couple of aliases — the visual upgrade was real but I wasn't looking at directory listings often enough for it to matter, unlike search and JSON parsing, which I do dozens of times a day. the_silver_searcher (ag) was ripgrep's direct predecessor in my toolkit and lost out specifically on speed once I compared them side by side on the same monorepo search — not a huge gap, but ripgrep won consistently enough that there was no reason to keep both installed.
The pattern in both cases is the same lesson as the seven tools that did stick: something that's merely nicer doesn't survive daily use the way something that removes a genuinely slow, frequent step does. A prettier ls is nicer. A search tool that's measurably faster on the exact searches I run all day is the kind of thing that changes a habit.
Installing all seven without doing it one at a time
On a fresh machine I install all seven in a single pass rather than waiting to rediscover I'm missing one mid-task, which is how I ended up defending a slow setup for so long in the first place — missing tools have a way of just not getting installed unless there's a checklist forcing the issue.
# macOS, via Homebrew
brew install ripgrep fzf jq httpie bat entr tealdeer
# tealdeer is a fast Rust implementation of the tldr client;
# the command it installs is still `tldr`
On Linux the package names are close to identical across most distributions' package managers (apt, dnf, pacman all carry current versions of each), with the same caveat that tldr's client implementations vary by name even though the command and the page format are standardized across all of them.
Chaining them together on a real problem
The point where these tools actually pay off isn't any one of them in isolation, it's chaining them. A recent example: production logs showed a spike in 500 errors from a specific endpoint, and I needed to find which recent commit touched that controller, check the exact error message across log files, and confirm the current code didn't already fix it.
rg "BookingController" --files-with-matches -t php | fzf
git log -p --since="3 days ago" -- app/Http/Controllers/BookingController.php | bat
rg "500" storage/logs/laravel-2026-08-1*.log | jq -R 'fromjson? | select(.level=="error")'
Three tools, about ninety seconds, no context switch to a GUI. That's the actual argument for learning any of these — not that they're individually clever, but that they compose into workflows a mouse-driven equivalent can't match for speed once they're muscle memory.
The learning curve nobody mentions
What the usual “here are some CLI tools” posts skip is that the first week with any of these is genuinely slower than your old habit, not faster. jq's filter syntax in particular reads like a foreign language the first few times — .data[] | {id, status} means nothing to your muscle memory yet, and it's tempting to give up and go back to eyeballing raw JSON. The tools that made this list survived that adjustment period because the payoff on the other side was large enough to push through a few days of feeling slower, not faster. If a tool doesn't clear that bar within a couple of weeks of genuine use, it's fair to drop it rather than force it.
What I'd tell someone starting from zero
- Install ripgrep and fzf first — shortest learning curve, most immediate payoff.
- Add jq and httpie once you're doing API work regularly.
- bat, entr, and tldr are smaller quality-of-life wins, worth having but not urgent.
All seven are cheap to install (a package manager one-liner on macOS or Linux) and every one of them earns its place in a dotfiles repo, which is the next thing worth getting right once the tools themselves are in place. I keep the exact install command in that repo too, so a future rebuild is a single copy-paste rather than a reconstruction from memory.
No comments yet.
Be the first visitor to add a thoughtful comment on this article.