macOS Terminal Productivity: 6 Tools That Replace 30

I spent three years tweaking my terminal.

Custom oh-my-zsh theme. Fourteen plugins. A .zshrc file so long it took noticeable seconds to open a new tab. I’d invested so much time configuring that I convinced myself all of it was essential.

Then one day I had to set up a fresh machine. And I realized: I could barely remember what half those plugins did. The ones I actually missed? I could count them on one hand.

That experience forced me to rethink macOS terminal productivity from scratch. Not “what cool tools exist?” but “what friction am I actually hitting every day, and what’s the minimum toolset to eliminate it?”

The answer turned out to be six tools and one brew install command.

The Four Friction Points Every Developer Hits

Before I list any tools, let me share the framework that changed how I think about the terminal.

Every terminal interaction follows the same loop: you have an intention, you translate it into a command, the machine executes it, and you read the output. Friction hides in four places:

Friction PointWhat It Feels LikeClassic Pain
Navigation“Let me cd through 7 nested folders…”Deep directory structures
Translation“What’s the find flag for file type again?”Forgotten syntax, Googling commands
Execution“Why is grep taking 30 seconds on this repo?”Slow legacy tools
Interpretation“Which of these 200 lines is the one I need?”Walls of unformatted text

Every tool I recommend below maps to one of these four. If it doesn’t clearly reduce a friction, it doesn’t make the cut.

Obsidian for Developers: Why I Chose It Over Notion and Never Looked Back

The One-Command Setup

Here’s the entire installation. If you don’t have Homebrew yet:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Then:

brew install fzf ripgrep bat eza zoxide

Five tools. One command. Under 60 seconds on a decent connection. Let me walk through each one.

zoxide: Stop Typing cd Paths (Navigation)

cd ~/Documents/Projects/iOS/MyApp/Sources/Features/Authentication — if you still type full paths like this, zoxide will save you a surprising amount of daily friction.

zoxide is a smarter cd replacement written in Rust. It tracks which directories you visit and how often, using a “frecency” algorithm (frequency + recency) to let you jump anywhere with a partial name.

# Add to ~/.zshrc
eval "$(zoxide init zsh)"
alias cd="z"

# After using it for a day or two:
z auth        # jumps to .../Features/Authentication
z myapp       # jumps to ~/Documents/Projects/iOS/MyApp
z obsidian    # jumps to your Obsidian vault

The first day it’s learning your habits, so you navigate normally. By day two, you type z plus a few characters and you’re there.

Pro tip: Use zi (interactive mode) when multiple directories match. It opens a fuzzy finder so you can pick the right one.

fzf: The Fuzzy Finder That Does Everything (Translation)

If I could only keep one tool from this list, it would be fzf. It’s a general-purpose fuzzy finder that plugs into everything — file search, command history, Git branches, processes.

The killer shortcuts after installation:

# Search command history with fuzzy matching
# Press Ctrl+R, then type any fragment you remember
# → finds that complex Docker command from last week

# Find any file by partial name
# Press Ctrl+T, then type
# → instantly filters thousands of files

# Jump to a directory
# Press Alt+C (or Option+C on macOS), then type
# → fuzzy directory navigation

fzf’s real power shows when you combine it with other tools. Add this to ~/.zshrc:

# Use fd instead of find for fzf (faster, respects .gitignore)
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND='fd --type=d --hidden --strip-cwd-prefix --exclude .git'

# Preview files with bat and directories with eza
show_file_or_dir_preview="if [ -d {} ]; then eza --tree --color=always {} | head -200; else bat -n --color=always --line-range :500 {}; fi"
export FZF_CTRL_T_OPTS="--preview '$show_file_or_dir_preview'"
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"

Now Ctrl+T shows a live syntax-highlighted preview of each file as you scroll through results. This alone is worth the entire setup.

ripgrep: grep, But 10x Faster (Execution)

ripgrep (rg) is the modern replacement for grep. Written in Rust, it searches recursively by default, respects your .gitignore, and is noticeably faster on large codebases.

# Old way
grep -r "viewDidLoad" . --include="*.swift"

# New way — faster, cleaner output, skips .git and build folders automatically
rg "viewDidLoad" --type swift

# Search with context (3 lines before and after)
rg "MQTT" -C 3

# Search only in specific file types
rg "TODO|FIXME" --type swift --type js

# Count matches per file
rg "import SwiftUI" --count

I don’t even alias grep to rg — I just naturally type rg now. The colored output with line numbers and file paths is so much easier to scan that going back to grep feels like reading raw logs.

Pro tip: Create a .ripgreprc in your home directory for persistent settings:

# ~/.ripgreprc
--smart-case
--hidden
--glob=!.git

Then add export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc" to your ~/.zshrc.

bat: cat With Syntax Highlighting (Interpretation)

bat is cat with wings. Syntax highlighting, line numbers, Git diff markers, and automatic paging for long files.

# Instead of cat
bat config.yaml
bat Package.swift
bat --diff main.swift  # show Git changes inline

# Use as a man page viewer (this is a game changer)
export MANPAGER="sh -c 'col -bx | bat -l man -p'"

After setting MANPAGER, your man pages suddenly have color and syntax highlighting. It’s one of those small changes that makes a surprising daily difference.

# Aliases for seamless use
alias cat='bat --paging=never'    # plain output for pipes
alias catt='bat'                   # full features with paging

eza: ls That Actually Tells You Something (Interpretation)

eza replaces ls with colored output, file icons, Git status indicators, and a tree view.

# My aliases in ~/.zshrc
alias ls="eza --color=always --icons"
alias ll="eza --color=always --long --git --icons"
alias lt="eza --color=always --tree --level=2 --icons"

The Git integration is what makes this essential. Running ll in a project directory shows which files are modified, staged, or untracked — right next to the filename. No need for a separate git status.

CI/CD for Indie Developers: How I Ship iOS Builds Without Thinking

The Real Reason 6 Tools Beat 30

Here’s what most “ultimate terminal setup” articles miss.

Every tool you add has two costs: time to install and configure, and the cognitive load of remembering it exists and how to use it. That second cost is invisible but real.

When I had 14 oh-my-zsh plugins, I used maybe 4 regularly. The rest added startup time and occasionally conflicted with each other.

These six tools map cleanly to the four friction points:

ToolFriction EliminatedReplaces
zoxideNavigationcd with long paths
fzfTranslationGoogling forgotten commands, manual file search
ripgrepExecutiongrep (slow, no .gitignore)
batInterpretationcat (no highlighting, no line numbers)
ezaInterpretationls (no icons, no Git status, no tree)
HomebrewMeta (install friction)Manual downloads

If a new tool doesn’t clearly beat what I already have at one of these friction points, it doesn’t make the cut. That single filter keeps your setup lean and your muscle memory stable.

The Complete .zshrc (Copy-Paste Ready)

Here’s my actual configuration, stripped to the essentials:

# ~/.zshrc — Minimal productive setup

# --- Homebrew ---
eval "$(/opt/homebrew/bin/brew shellenv)"

# --- Zoxide (smarter cd) ---
eval "$(zoxide init zsh)"
alias cd="z"

# --- fzf (fuzzy finder) ---
source <(fzf --zsh)
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND='fd --type=d --hidden --strip-cwd-prefix --exclude .git'

show_file_or_dir_preview="if [ -d {} ]; then eza --tree --color=always {} | head -200; else bat -n --color=always --line-range :500 {}; fi"
export FZF_CTRL_T_OPTS="--preview '$show_file_or_dir_preview'"
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"

# --- ripgrep ---
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"

# --- bat (better cat) ---
alias cat='bat --paging=never'
export MANPAGER="sh -c 'col -bx | bat -l man -p'"

# --- eza (better ls) ---
alias ls="eza --color=always --icons"
alias ll="eza --color=always --long --git --icons"
alias lt="eza --color=always --tree --level=2 --icons"

# --- Zsh plugins (only 2 you actually need) ---
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

# --- Useful aliases ---
alias ..="cd .."
alias ...="cd ../.."
alias g="git"
alias gst="git status"
alias gp="git push"
alias gc="git commit"

Install the two zsh plugins:

mkdir -p ~/.zsh
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ~/.zsh/zsh-syntax-highlighting

Total setup time from a fresh Mac: under 10 minutes.

What I Intentionally Left Out

A few popular tools that didn’t make the cut — and why:

oh-my-zsh: Great for beginners, but it loads hundreds of completions you’ll never use. My tab opens instantly now instead of the 2-4 second delay I had with oh-my-zsh. The two zsh plugins above give you 90% of the value.

Starship prompt: Beautiful, but not essential. If you want it, brew install starship and add eval "$(starship init zsh)". Nice-to-have, not need-to-have.

tmux: Powerful for remote sessions and persistent layouts, but most macOS developers can use native Terminal tabs or iTerm2 panes. I only reach for tmux when SSH’d into a server.

Warp / Ghostty / iTerm2: Terminal emulator choice is personal preference. I’ll say this: switching the six CLI tools above gives you far more productivity gain than switching your emulator.

Frequently Asked Questions

Do these tools work with bash instead of zsh?

Yes. ripgrep, bat, eza, fzf, and zoxide are all shell-agnostic binaries. The initialization syntax changes slightly (e.g., eval "$(zoxide init bash)"), but the tools themselves work the same.

Will this slow down my terminal startup?

No. These are all compiled Rust binaries that load in milliseconds. This setup adds less than 100ms to shell startup — far less than oh-my-zsh with its default plugin set.

What about fd? You mentioned it but didn’t list it as essential.

fd is a great find replacement, and fzf uses it for better file searching if it’s installed. Run brew install fd — I consider it a “seventh tool” worth adding but not strictly required.

Can I use these alongside oh-my-zsh?

Yes. Add the alias and eval lines to your existing ~/.zshrc. The tools work regardless of your zsh framework.


The best terminal setup isn’t the one with the most tools. It’s the one where every tool earns its place by eliminating a real friction point. Install these six, give them a week of daily use, and you won’t go back.

댓글 남기기