Zsh Cheatsheet - .zshrc, Aliases & Completion
After switching the default shell, the speedup does not come from syntax — it comes from smarter completion, prefix-aware history search, and a prompt that doubles as a status display. The sheet is organised around the seven parts of .zshrc people keep editing: base options, variables and arrays, globbing and expansion, history, functions and completion, prompt customisation, and oh-my-zsh with plugins. A few gotchas are called out: zsh arrays index from 1 while bash arrays index from 0, which is the most common source of breakage when porting scripts. setopt AUTO_CD lets you hit enter on a directory name, and pairs with AUTO_PUSHD to turn cd - into a jump list. EXTENDED_GLOB is what makes ** genuinely recursive rather than one level deep. Binding the arrow keys to history-search-backward turns them from a time scrollbar into a prefix search over past commands. On oh-my-zsh, remember it adds measurable startup cost, so cherry-pick plugins on production boxes.
Typical Use Case
For developers who have just moved their default shell to zsh: make completion, history search, aliases and the prompt actually do the work. What zsh adds over bash concentrates in three places — recursive globbing (**), copyable history search (Ctrl+R), and glob qualifiers such as *(om[1]) to pick the newest file. This sheet covers the high-traffic .zshrc options and oh-my-zsh plugin usage; best read once in the first week after switching, then revisit as needed.
Basic Setup 5
chsh -s $(which zsh)source ~/.zshrcecho $SHELLsetopt AUTO_CDsetopt CORRECTVariables & Arrays 6
NAME="value"arr=(a b c)echo $arr[1]echo ${arr[@]}${#arr[@]}typeset -A dict
dict[key]=valueGlobbing & Expansion 6
**/*.js*.{js,ts}*(.)*(/)*(om[1])=lsHistory & Search 6
HISTSIZE=10000 / SAVEHIST=10000setopt SHARE_HISTORYCtrl+R!!!$history -i | tailFunctions & Completion 4
function name() { ... }alias ll="ls -la"autoload -Uz compinit && compinitcompdef _git g=gitPrompt Customization 5
PROMPT='%n@%m %~ %# '%n / %m / %M%~ / %dRPROMPT="%T"%T / %D / %Woh-my-zsh & Plugins 5
plugins=(git zsh-autosuggestions zsh-syntax-highlighting)ZSH_THEME="robbyrussell"zsh-autosuggestionszsh-syntax-highlightingextract file.tar.gzParameter matrix
| Parameter | Effect | Example |
|---|---|---|
setopt AUTO_CD | Typing a directory name enters it, no need to write cd | setopt AUTO_CD |
setopt CORRECT | Prompt to correct a misspelled command | setopt CORRECT |
HISTSIZE / SAVEHIST | History counts for memory and file; both must be set to take effect | HISTSIZE=10000; SAVEHIST=10000 |
setopt SHARE_HISTORY | Multiple terminals share history in real time | setopt SHARE_HISTORY |
Ctrl+R | Reverse incremental search of command history | Type a git keyword after Ctrl+R |
!! | Run the previous command; sudo !! is the classic combo | sudo !! |
!$ | The last argument of the previous command | mkdir -p /var/log/app; cd !$ |
**/*.js | Recursively match .js files at any level | ls **/*.js |
*.{js,ts} | Brace expansion, matching multiple extensions at once | ls *.{js,ts} |
*(om[1]) | glob qualifier: pick the most recently modified file | ls -t *(om[1]) |
compdef _git g | Reuse git completion for the alias g | compdef _git g=git |
%~ / %n / %T | Prompt placeholders: current directory / username / time | PROMPT='%n@%m %~ %# ' |
Common pitfalls
SymptomAfter switching a script from bash to zsh, array lookups all come back empty and ${arr[0]} does not yield the first element.
Causezsh arrays are 1-indexed by default, whereas bash starts at 0.
FixUse ${arr[1]}, or run emulate sh / setopt KSH_ARRAYS to make the behavior closer to bash.
SymptomAfter defining an alias in .zshrc, continuing to use that alias on the same line has no effect.
CauseAn alias only takes effect for commands after it within the same read.
FixPut the alias on its own line, or switch to a function function name() { ... }.
SymptomAfter installing zsh-syntax-highlighting, syntax highlighting does not work or errors out.
CauseThe plugin load order is wrong; the highlighter must be loaded last in the plugins array.
FixWrite plugins=(git zsh-autosuggestions zsh-syntax-highlighting) and put the highlighter at the end.
SymptomAfter switching to zsh you cannot get an interactive shell and have to fall back to sh.
Cause~/.zshrc has a syntax error that breaks parsing at startup.
FixUse zsh -n ~/.zshrc for a syntax check (parse only, do not execute), locate the bad line, and comment it out first.
SymptomThe gray suggestion from zsh-autosuggestions is not accepted with the arrow keys.
CauseThe default accept key is → (right arrow); pressing End or space does nothing.
FixPress → to accept the whole suggestion; accepting only one word needs extra configuration.
SymptomA command found with Ctrl+R turns out to have wrong arguments, but only that one entry is in history.
CauseThe variants of that command were not saved in history.
FixIncrease the history size: HISTSIZE=10000 SAVEHIST=10000, and use history -i | tail to see timestamped history.
Troubleshooting
1Confirm the current shell and whether the config is in effect
echo $SHELL && zsh -n ~/.zshrcThe first shows the login shell; the second only does a syntax check (-n) and locates parse errors in .zshrc.
2Reload immediately after changing the config
source ~/.zshrcRun it once after every edit of .zshrc; you can save effort with alias reload-cfg="source ~/.zshrc".
3Recursively find .js files at any level
ls **/*.js** is zsh recursion wildcard; bash needs globstar enabled first (shopt -s globstar).
4Get the most recently modified log file
ls -t *(om[1])(om[1]) is a glob qualifier; o sorts by modification time and takes the first; bash needs find + printf.
5Search history for a command containing a keyword and run it
git rebaseType the prefix then press Ctrl+R to search upward and Enter to run; with SHARE_HISTORY multiple terminals share in real time.
Command Examples
Recall a matching command from history
git rebaseType git rebase in the terminal and press Ctrl+R to search upward for history containing that prefix; the arrow keys or Enter run it directly. With setopt SHARE_HISTORY, history is shared across terminals in real time.
Reuse the last argument of the previous command
mkdir -p /var/log/myapp
cd !$!$ expands to the last argument of the previous command, !^ is the first, !! is the whole command. sudo !! is the classic combo — run a dangerous command, then rerun it with the same arguments prefixed by sudo.
Recursively match files at any depth
ls **/*.ts
ls *(om[1]).log** recursively matches all levels (bash needs globstar enabled); *(om[1]) is a glob qualifier that takes the most recently modified .log file. bash needs find with -printf to do the same.
Output
src/index.ts src/api/client.ts src/api/auth/login.ts
Reload the config immediately
source ~/.zshrcRun it once after every edit; writing alias reload-cfg="source ~/.zshrc" is more convenient. Note that an alias does not apply to its own line within the same file.
Common Pitfalls
- zsh arrays are 1-indexed, so ${arr[0]} is empty — the most common porting trap from bash.
- An alias only takes effect on subsequent lines; defining and using it on the same line does nothing.
- Plugin order matters: zsh-syntax-highlighting must be loaded last in the plugins array.
- ${arr[@]} expands differently in zsh than bash, so quote it explicitly in portable scripts.
- Verify ~/.zshrc parses before switching your login shell — one syntax error can leave you without a working interactive prompt.
Tips
- Install oh-my-zsh: sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
- zsh-autosuggestions needs a separate install (git clone into $ZSH_CUSTOM/plugins).
- setopt AUTO_CD lets you cd by typing a dir name.
- Bind up/down arrows to prefix history search via bindkey.
- zsh arrays start at 1 (bash starts at 0) - mind this when porting scripts.
- ZDOTDIR changes the config dir, handy for isolated configs.
FAQ
Do zsh arrays start at index 0 or 1?
zsh indexes arrays from 1, while bash starts at 0. This is one of the most common porting traps: in zsh ${arr[0]} is an empty element, not the first one, and the correct form is ${arr[1]}. To make zsh behave more bash-like, use emulate sh or setopt KSH_ARRAYS.
Beyond Ctrl+R, what history tricks does zsh offer?
Ctrl+R does reverse incremental search, and pressing it again walks further back. Beyond that: !! repeats the previous command, making sudo !! the classic pairing; !$ expands to the last argument of the previous command, so after mkdir -p /var/log/app, cd !$ lands you there; !^ grabs the first argument. And setopt SHARE_HISTORY shares history live across terminal windows.
Where is zsh globbing stronger than bash?
Three main things. ** recurses into subdirectories, which bash needs globstar for. Brace expansion *.{js,ts} matches several extensions in one pattern instead of listing them. And glob qualifiers let you filter: *(.) regular files only, *(/) directories only, *(om[1]) the single most recently modified one. In bash you would need find for equivalent filtering.
How do I set up syntax highlighting and autosuggestions in zsh?
Two plugins do it: zsh-syntax-highlighting highlights command syntax live (invalid commands turn red) and zsh-autosuggestions shows a grey inline suggestion from your history that you accept with the right arrow. Add plugins=(git zsh-autosuggestions zsh-syntax-highlighting) to .zshrc and enable the completion system with compinit. Make sure the highlighter is loaded last in the plugins array.
What do %~, %n and %T mean in the zsh prompt?
%n is the username, %m the short hostname, %M the full hostname. %~ is the current path with the home directory abbreviated to ~, while %d prints the absolute path. %T is the time in 24-hour form, %D the year-month-day, %W the month-day-year. The classic PROMPT='%n@%m %~ %# ' shows user@host path plus a prompt char, where %# renders as $ for a normal user and # for root.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us