Cheat Sheet

zsh Cheat Sheet

zsh has been the default shell on macOS since Catalina and is a drop-in upgrade for bash on Linux. This sheet covers history search, aliases, keybindings, completion, globbing, .zshrc setup, and the Oh My Zsh git aliases.

Last updated September 5, 2026

CommandWhat it does
Search history as you type (press again for older matches)
Show the last 16 commands
Show the whole history
Search history for a command
Rerun the last command ( reruns it as root)
Last argument of the previous command
All arguments of the previous command
Rerun the most recent command starting with ssh
Rerun history entry 42
Insert the previous command's last argument (repeat to go older)
after typing Only steps through matching commands if you bind prefix search (below)

History size and behaviour go in :

HISTSIZE=50000
SAVEHIST=50000
setopt SHARE_HISTORY          # share history across open terminals
setopt HIST_IGNORE_ALL_DUPS   # keep one copy of a repeated command
setopt HIST_IGNORE_SPACE      # commands starting with a space are not saved

# Up/Down search commands starting with what you typed
bindkey '^[[A' history-beginning-search-backward
bindkey '^[[B' history-beginning-search-forward

Keyboard Shortcuts

Emacs-style bindings, the default. See the next section for vi mode.

KeyAction
/ Start / end of line
/ Forward / back one word
Delete the word before the cursor
Delete the whole line
Delete from cursor to end of line
Paste what Ctrl+W/U/K deleted
Clear the screen
Cancel the current line or interrupt the running command
Log out on an empty line; delete char otherwise
Suspend the foreground job ( resumes)
Complete; press again to cycle candidates
Edit the current line in $EDITOR (after )

Aliases

CommandWhat it does
Define an alias for this session
List every defined alias
Show one alias's definition
Remove an alias
Run the real command, ignoring the alias ( also works)
Global alias, expands anywhere in the line:
Suffix alias: typing opens it in less
Typing opens it in VS Code

Aliases live for one session unless you put them in :

echo "alias ll='ls -lah'" >> ~/.zshrc
source ~/.zshrc

Completion

zsh's completion system knows flags, hostnames, git branches, and PIDs, but only after you turn it on.

CommandWhat it does
Enable completion (put in )
Complete; a second Tab lists candidates
(with menu select)Arrow-key menu over the candidates
Turn on the arrow-key menu
Case-insensitive completion
Rebuild the cache when completions go stale
Fix the "compinit: insecure directories" warning

Keybindings and Vi Mode

CommandWhat it does
Emacs mode (the default)
Vi mode: Esc for normal mode, back to insert
List current bindings
Restore Ctrl+R in vi mode (not bound there by default)
Make Esc register instantly in vi mode (in )
See what a specific key runs

In vi normal mode: / step through history, searches it, opens the line in your editor.

Globbing

zsh globbing does what you would otherwise need for. Recursive works out of the box.

PatternWhat it matches
All .js files, recursively
Regular files only
Directories only
Symlinks only
The most recently modified file
The five most recently modified
Files larger than 10 MB
All .txt except notes.txt (needs extendedglob)
Everything except .md files (needs extendedglob)
Files, and no error when nothing matches
setopt extendedglob   # enables ^negation and the ~exclusion operator

For heavier searches (by mtime, with -exec), see the find cheat sheet.

Startup Files

Read in this order. macOS Terminal and iTerm open login shells, so and both run; most Linux terminals open non-login shells, so only runs.

FileWhen it runsPut here
Every zsh, even scriptsAlmost nothing; keep it minimal
Login shells, oncePATH exports,
Every interactive shellAliases, functions, prompt, keybindings, completion
Login shells, after zshrcRarely used
When a login shell exitsCleanup, rarely used

After editing any of them: (or open a new tab).

Prompt

CommandWhat it does
user@host, current directory, then % (# as root)
Just the last path component
Colour a segment ( on, off)
Right-side prompt showing the time
Enable the built-in theme system
List built-in themes ( tries one)

Common escapes: user, host, directory with , % or #, time, last exit code. Most people skip hand-rolling and install powerlevel10k or starship, which come with git status, exit codes, and language versions built in.

Oh My Zsh

A config framework: themes, completion tweaks, and plugins in one install. Everything lives in after it is set up.

CommandWhat it does
Enable plugins (edit the line in )
Pick a theme
Update Oh My Zsh
List available plugins
Apply config changes to the current session

The git plugin is why most people install it. The aliases you will actually use:

AliasExpands to
/ /
current branch
/ /

Run to see the full list (150+).

Command Not Found Fixes

means the binary is not on your PATH or is not a binary at all. The pattern is the same for brew, pip, npm, nvm, docker, and code.

SymptomFix
(Apple Silicon)Add to , open a new tab
Any tool you know is installed, then add its directory: in
Installed seconds ago, still not found so zsh refreshes its command cache
nvm is a function; its init lines belong in , run the installer again or copy them over
Worked in bash, gone in zshMove PATH exports from / into
In VS Code: Cmd+Shift+P, "Shell Command: Install 'code' command in PATH"

One-Liners and Substitution

CommandWhat it does
Run the second only if the first succeeds
Run both regardless
Run the second only if the first fails
Capture a command's output in a variable
Substitute output inline
Arithmetic
Loop over files on one line

zsh vs bash

Differencezshbash
Unquoted with spacesStays one wordSplits into words
Array indexingStarts at 1 ()Starts at 0 ()
Recursive glob Built inNeeds
Unmatched globError: Pattern passed through as-is
Config file
Prompt variable with escapes with escapes
Spelling correction, suffix aliases, glob qualifiersYesNo

Scripts are unaffected: a shebang runs the script in bash whatever your login shell is. Write new scripts for the shell you name in the shebang.

Gotchas

  • when a URL contains or : zsh globs the argument. Quote it () or .
  • comments do not work at the interactive prompt by default: (Oh My Zsh turns this on for you).
  • Pasted multi-line snippets run line by line as they land. Paste into (editor) if you want to review first.
  • A new PATH entry in only applies to new shells; fixes the current one.
  • zsh writes each terminal's history at exit by default; if you want tabs to see each other's commands live.
  • Long remote sessions die with the connection. Run zsh inside tmux on servers so your shell survives a dropped SSH connection.

zsh Cheat Sheet FAQ

Why is zsh the default shell on Mac?
Apple switched the default from bash to zsh in macOS Catalina (2019) because the bash it shipped was stuck at version 3.2 from 2007; newer bash releases moved to the GPLv3 license, which Apple avoids. zsh is under a permissive license, so Apple can ship a current version. For interactive use zsh does everything bash 3.2 did and more. If you prefer bash anyway, run chsh -s /bin/bash, but note that scripts starting with #!/bin/bash still run in bash either way; the default shell only affects your interactive terminal.
How do I fix zsh: command not found?
The command is either not installed or not on your PATH. Run echo $PATH and check whether the directory holding the binary is listed. If not, add export PATH="/path/to/dir:$PATH" to ~/.zshrc and run source ~/.zshrc. On an Apple Silicon Mac, Homebrew installs to /opt/homebrew, which is not on the default PATH, so command not found: brew (and everything brew installed) is fixed by adding eval "$(/opt/homebrew/bin/brew shellenv)" to ~/.zprofile. If you just installed the tool in this session, run rehash so zsh notices the new binary. Tools like nvm are shell functions, not binaries: their installer appends init lines to your shell config, and those lines must live in ~/.zshrc, not a leftover ~/.bash_profile.
How do I make an alias permanent in zsh?
An alias typed at the prompt dies with the session. Put the line in ~/.zshrc, which zsh reads at the start of every interactive session: echo "alias ll='ls -lah'" >> ~/.zshrc, then source ~/.zshrc to load it now. Quote the definition so the shell does not expand it while you are writing it. If the alias does not survive a new terminal, check you edited ~/.zshrc and not ~/.bashrc, a common leftover habit after switching from bash, and check that nothing later in the file redefines or unaliases it.
What is the difference between .zshrc and .zprofile?
~/.zprofile runs once per login shell, ~/.zshrc runs for every interactive shell. Put environment setup that should run once, like PATH exports and eval "$(brew shellenv)", in ~/.zprofile; put aliases, functions, keybindings, completion setup, and prompt config in ~/.zshrc. On macOS every new terminal tab is a login shell, so both files run and the split is mostly about tidiness. On Linux, terminal windows are usually interactive non-login shells, so only ~/.zshrc runs; anything only in ~/.zprofile will be missing until you log in fresh. ~/.zshenv runs for every zsh instance including scripts, so keep it minimal.
Do bash commands work in zsh?
Day to day, yes: the commands you type (ls, grep, ssh, git) are programs, not part of the shell, and pipes, redirection, &&, and $(command) all work the same. The differences bite in scripting and edge cases: zsh does not word-split unquoted variables, its arrays start at 1, and an unmatched glob is an error instead of being passed through. Bash scripts with a #!/bin/bash shebang keep running in bash regardless of your login shell, so nothing breaks there. What does not carry over automatically is your config: aliases and PATH lines in ~/.bashrc or ~/.bash_profile must be moved to ~/.zshrc.

Related cheat sheets