macOS Terminal Setup Guide: zsh, Customization & Essential Commands
The terminal is the most powerful application on your Mac, and it's already installed. Once you're comfortable in it, tasks that take a dozen clicks in the Finder become a single line, and everything from Git to servers to AI coding agents runs through it.
This guide takes you from "I open Terminal occasionally" to a fast, comfortable, well-customized setup. We'll cover how the shell works on macOS, the commands worth memorizing, how to customize your prompt and shell, and the modern command-line tools that make a real difference. Everything here works with the built-in Terminal — and even better in a dedicated terminal app (more on that below).
Opening the Terminal and Understanding Your Shell
Open Terminal from Applications → Utilities, or just press Cmd+Space and type "Terminal." You'll see a prompt waiting for input.
Since macOS Catalina (2019), the default shell is zsh (the Z shell). Older guides reference bash; the commands are mostly identical, but configuration lives in different files. To confirm what you're running:
echo $SHELL
# /bin/zsh
If you're on bash and want the modern default, switch with:
chsh -s /bin/zsh
zsh is backward-compatible with most bash usage but adds better tab completion, smarter globbing, and a thriving ecosystem of themes and plugins. The rest of this guide assumes zsh.
A quick note on the app itself: Apple's Terminal is fine for getting started, but a dedicated terminal renders faster and adds tabs, splits, and session persistence. If you outgrow it, see our comparison of the best Mac terminals.
The Essential Commands
You don't need to memorize hundreds of commands — you need fluency with a couple dozen. Here are the ones that come up constantly.
Navigating and inspecting:
pwd # print working directory (where am I?)
ls -lah # list files: long format, all (incl. hidden), human sizes
cd ~/Projects # change directory (~ is your home folder)
cd - # jump back to the previous directory
open . # open the current folder in Finder
Working with files and folders:
mkdir -p a/b/c # create nested folders in one go
cp -R src dest # copy a folder recursively
mv old new # move or rename
rm -i file # remove, prompting before each delete (safer)
touch file.txt # create an empty file / update its timestamp
Reading and searching:
cat file.txt # print a file
less file.txt # page through a long file (q to quit)
head -n 20 file.txt # first 20 lines
tail -f server.log # follow a log live
grep -rn "TODO" . # recursively find "TODO" with line numbers
Processes and the system:
top # live process list (q to quit)
ps aux | grep node # find a running process
kill -9 <pid> # force-quit a process by id
lsof -i :3000 # what's using port 3000?
df -h # disk space, human-readable
Networking:
If a development server reports that its port is occupied, the macOS port troubleshooting guide shows how to identify the listener, find its project, and resolve the collision.
curl -I https://example.com # fetch just the headers
ping example.com # check connectivity (Ctrl+C to stop)
ipconfig getifaddr en0 # your local IP address
A few habits make these safer and faster: use rm -i until deleting is muscle memory, lean on Tab completion for paths (start typing and press Tab), and remember that Ctrl+C cancels a running command while Ctrl+R searches your history.
Configuring zsh with ~/.zshrc
Your shell reads ~/.zshrc every time it starts. This file is where you set environment variables, define shortcuts, and initialize tools. Open it with any editor:
nano ~/.zshrc # or: code ~/.zshrc / vim ~/.zshrc
After editing, apply changes without restarting the terminal:
source ~/.zshrc
A sensible starting point for history behavior — bigger history, no duplicates, shared across tabs:
HISTSIZE=50000
SAVEHIST=50000
setopt SHARE_HISTORY # share history between sessions
setopt HIST_IGNORE_ALL_DUPS # drop older duplicate commands
setopt HIST_REDUCE_BLANKS # tidy up whitespace
This alone makes Ctrl+R history search far more useful.
Install Homebrew (the Missing Package Manager)
Almost everything below is installed with Homebrew, the de facto package manager for macOS. Install it once:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
On Apple Silicon Macs, add Homebrew to your PATH by putting this in ~/.zshrc:
eval "$(/opt/homebrew/bin/brew shellenv)"
Now installing tools is one line each: brew install <name>. Update everything with brew update && brew upgrade.
A Better Prompt with Starship
The default prompt is functional but tells you little. Starship is a fast, cross-shell prompt that shows your Git branch and status, the language version for the project you're in, exit codes, and more — and it's asynchronous, so it stays snappy.
brew install starship
Then add this as the last line of ~/.zshrc:
eval "$(starship init zsh)"
Open a new terminal and you'll have a context-aware prompt instantly. Customize it in ~/.config/starship.toml if you want to tweak symbols, colors, or which modules show. If you prefer to stay vanilla, you can craft a PROMPT string by hand in zsh, but Starship gives you 90% of what most people want with zero fuss.
Aliases and Functions: Stop Typing the Same Things
Aliases turn long commands into short ones. Add these to ~/.zshrc:
alias ll='ls -lah'
alias gs='git status'
alias gp='git pull'
alias ..='cd ..'
alias ...='cd ../..'
alias reload='source ~/.zshrc'
For anything that needs an argument, use a function instead. A classic: make a directory and step into it in one move:
mkcd() { mkdir -p "$1" && cd "$1"; }
Now mkcd new-project creates the folder and drops you inside it. Build up a small collection of these over time — they compound.
Modern CLI Tools Worth Installing
The classic Unix tools are decades old and still work, but a wave of modern replacements are faster, friendlier, and prettier. None are required, but together they transform the experience:
| Modern tool | Replaces | Why it's better |
|---|---|---|
| eza | ls |
Colors, icons, a --tree view, Git status per file |
| bat | cat |
Syntax highlighting, line numbers, paging |
ripgrep (rg) |
grep |
Dramatically faster, respects .gitignore by default |
| fd | find |
Simpler syntax, fast, sensible defaults |
| fzf | — | Fuzzy finder for files, history, and anything piped in |
| zoxide | cd |
Jumps to directories by frecency: z proj |
| btop | top |
A beautiful, interactive system monitor |
| delta | git diff |
Side-by-side, syntax-highlighted diffs |
| jq | — | Slice and query JSON from the command line |
| tldr | man |
Practical examples instead of exhaustive manuals |
Install the set in one go:
brew install eza bat ripgrep fd fzf zoxide btop git-delta jq tlrc
Then wire up the two that need initialization in ~/.zshrc:
# zoxide: smarter cd — use `z <partial-name>`
eval "$(zoxide init zsh)"
# fzf: fuzzy history (Ctrl+R) and file search (Ctrl+T)
source <(fzf --zsh)
# make eza the default ll
alias ll='eza -lah --git --icons'
alias cat='bat'
After this, Ctrl+R becomes an interactive fuzzy search through your command history — one of the biggest single upgrades to terminal life.
Keyboard Shortcuts That Save Real Time
The shell uses Emacs-style line editing by default. These work in any zsh prompt:
Ctrl+A/Ctrl+E— jump to the start / end of the lineCtrl+U/Ctrl+K— delete to the start / end of the lineCtrl+W— delete the previous wordCtrl+R— reverse-search your history (incredible with fzf)Ctrl+L— clear the screen (keeps your command)Ctrl+C— cancel the current commandCtrl+D— end of input / close the shellOption+←/Option+→— move word by word (enable "Use Option as Meta key" in your terminal settings)
Memorize Ctrl+A, Ctrl+E, Ctrl+R, and Ctrl+W first — they'll change how it feels to type commands.
SSH: Connecting to Servers Properly
Sooner or later you'll work on a remote machine. Generate a modern key pair once:
ssh-keygen -t ed25519 -C "you@example.com"
Copy your public key to a server so you can log in without a password:
ssh-copy-id user@your-server.com
ssh user@your-server.com
Stop typing full host strings by defining shortcuts in ~/.ssh/config:
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
Host *
AddKeysToAgent yes
UseKeychain yes
Now ssh prod is all you need, and macOS will remember your key passphrase in the Keychain. To move files, scp file user@host:/path works, and rsync -avz local/ user@host:/remote/ is better for syncing folders. (If you do a lot of remote work, a terminal with a built-in file browser saves a lot of scp gymnastics — more below.)
Keeping Sessions Alive: tmux, zellij, and Beyond
A plain terminal loses everything when it closes or your laptop sleeps mid-task. Two tools fix that by running a persistent session you can detach from and reattach to later:
brew install tmux # the classic, ubiquitous multiplexer
brew install zellij # a modern, friendlier alternative with discoverable keybinds
Start tmux, run your long process, detach with Ctrl+B then D, and reattach later with tmux attach. Your work keeps running the whole time. This is essential for remote sessions and long builds.
Some terminals build persistence in so you don't have to think about it. If your workflow centers on running AI coding agents — keeping Claude Code or Codex alive across restarts, in split sessions, with files and SSH alongside — a purpose-built app like Agents UI handles persistence, splits, an editor, and remote file browsing natively, so you're not stitching it together with tmux and scp. For a traditional setup, tmux or zellij plus your favorite terminal works great too.
Make It Portable: Dotfiles
Once your setup is dialed in, don't lose it. Put ~/.zshrc, ~/.ssh/config (without private keys), ~/.config/starship.toml, and any other config into a Git repository — your "dotfiles." Then on a new Mac you can clone it and symlink the files back, and you're home in minutes instead of rebuilding from memory.
A minimal approach:
mkdir ~/dotfiles && cd ~/dotfiles
git init
cp ~/.zshrc ./zshrc
ln -sf ~/dotfiles/zshrc ~/.zshrc
From there, commit and push to a private repo. Plenty of frameworks exist (chezmoi, GNU Stow, yadm), but even a folder of files and a few symlinks gets you 90% of the benefit.
A Suggested Starting ~/.zshrc
Pulling it together, here's a clean baseline you can adapt:
# Homebrew (Apple Silicon)
eval "$(/opt/homebrew/bin/brew shellenv)"
# History
HISTSIZE=50000
SAVEHIST=50000
setopt SHARE_HISTORY HIST_IGNORE_ALL_DUPS HIST_REDUCE_BLANKS
# Aliases
alias ll='eza -lah --git --icons'
alias cat='bat'
alias gs='git status'
alias ..='cd ..'
alias reload='source ~/.zshrc'
# Functions
mkcd() { mkdir -p "$1" && cd "$1"; }
# Tools
eval "$(zoxide init zsh)"
source <(fzf --zsh)
# Prompt (keep this last)
eval "$(starship init zsh)"
Where to Go Next
You now have a fast, comfortable, well-organized terminal: a modern shell, a smart prompt, better tools, and the muscle memory to move quickly. The best way to get fluent is to use it for things you'd normally do in a GUI — copy files, search code, manage Git — until reaching for the mouse feels slower.
When you're ready to upgrade the terminal app itself, our guide to the best terminals for Mac in 2026 walks through the options, from minimalist speed demons to tools built for AI-agent workflows. Either way, the setup above will follow you wherever you go.