zsh — the Z Shell with Powerful Globbing and Completion
Use zsh productively: globbing, glob qualifiers, arrays, completion, setopt and Oh My Zsh – the Z shell beyond plain bash.
zsh (the Z shell) is largely bash-compatible but adds serious power on top: rich tab completion, recursive globbing with glob qualifiers, 1-based arrays and a long list of setopt switches. It has been the default shell on macOS since Catalina; on Linux you switch with chsh -s $(which zsh). Frameworks like Oh My Zsh and Prezto ship themes, plugins and sensible defaults out of the box. This guide focuses on the features that make zsh more productive than plain bash.
Globbing & Pattern Matching
ls **/*.txt — Recursive globbing. Match files in all subdirectories (enabled by default).
ls **/*.jsonls *(.) — Glob qualifier: match only regular files.
ls -la *(.)ls *(/) — Glob qualifier: match only directories.
ls -d *(/)ls *(@) — Glob qualifier: match only symbolic links.
ls -la *(@)ls *(om[1,5]) — Glob qualifier: 5 most recently modified files. o=order, m=mtime.
ls -la *(om[1,5])ls *(Lk+100) — Glob qualifier: files larger than 100 KB. L=size, k=KB, +=greater.
ls -lh *(Lk+100)ls *(.mh-1) — Glob qualifier: files modified in the last hour. m=mtime, h=hours.
ls -la *(.mh-1)ls (#i)pattern — Case-insensitive glob matching (requires EXTENDED_GLOB).
setopt EXTENDED_GLOB; ls (#i)readme*ls ^pattern — Negation glob. Match everything except pattern (requires EXTENDED_GLOB).
setopt EXTENDED_GLOB; ls ^*.logParameter Expansion
${(U)VAR} — Convert string to uppercase.
name='hello'; echo "${(U)name}" # HELLO${(L)VAR} — Convert string to lowercase.
NAME='WORLD'; echo "${(L)NAME}" # world${(C)VAR} — Capitalize first letter of each word.
str='hello world'; echo "${(C)str}" # Hello World${(s:sep:)VAR} — Split string into an array by separator.
PATH_PARTS=(${(s/:/)PATH}); echo "${PATH_PARTS[1]}"${(j:sep:)ARRAY} — Join array elements with separator.
arr=(a b c); echo "${(j:,:)arr}" # a,b,c${(t)VAR} — Show the type of a variable (scalar, array, integer, etc.).
arr=(1 2 3); echo "${(t)arr}" # array${(u)ARRAY} — Remove duplicate elements from an array (unique).
arr=(a b a c b); echo "${(u)arr}" # a b c${(o)ARRAY} / ${(O)ARRAY} — Sort array in ascending / descending order.
arr=(cherry apple banana); echo "${(o)arr}"Arrays & Associative Arrays
arr=(val1 val2 val3) — Declare an indexed array. Zsh arrays are 1-based (not 0-based like Bash).
colors=(red green blue); echo "$colors[1]" # redecho "$arr[1]" — Access first element (1-based indexing, unlike Bash).
echo "$colors[2]" # greenecho "$arr[-1]" — Access last element using negative index.
echo "$colors[-1]" # blueecho "$arr[2,4]" — Array slice from index 2 to 4 (inclusive).
nums=(10 20 30 40 50); echo "$nums[2,4]" # 20 30 40typeset -A map — Declare an associative array.
typeset -A ports; ports=(http 80 https 443)echo "${(k)map}" — Get all keys of an associative array.
echo "${(k)ports}" # http httpsecho "${(kv)map}" — Get all key-value pairs of an associative array.
echo "${(kv)ports}" # http 80 https 443History & Navigation
Ctrl+R — Incremental reverse history search.
Ctrl+R, then type to search!! — Repeat the last command.
sudo !!!$ — Last argument of the previous command.
mkdir mydir; cd !$!* — All arguments of the previous command.
echo foo bar baz; echo !*!<string> — Run the most recent command starting with string.
!dockerfc — Open last command in $EDITOR for editing and re-execution.
fchistory 1 — Show full command history (Zsh numbers from 1).
history 1 | grep sshsetopt SHARE_HISTORY — Share history between all running Zsh sessions.
setopt SHARE_HISTORYTab Completion
Tab — Complete command, path, or argument. Shows menu on ambiguity.
git che<Tab> # completes to git checkoutTab Tab — Cycle through completion options in menu.
cd /u<Tab><Tab> # cycles through /usr, /Users, etc.compinit — Initialize the completion system. Usually in .zshrc.
autoload -Uz compinit && compinitzstyle ':completion:*' menu select — Enable interactive menu selection for completions.
zstyle ':completion:*' menu selectzstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' — Enable case-insensitive tab completion.
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'Shell Options (setopt)
setopt AUTO_CD — Type directory name to cd into it (no cd needed).
setopt AUTO_CD; /tmp # same as cd /tmpsetopt CORRECT — Enable spelling correction for commands.
setopt CORRECT; gti status # suggests: git?setopt CORRECT_ALL — Enable spelling correction for commands and arguments.
setopt CORRECT_ALLsetopt NO_CASE_GLOB — Make globbing case-insensitive.
setopt NO_CASE_GLOB; ls *.TXT # matches .txt toosetopt EXTENDED_GLOB — Enable extended globbing operators (^, ~, #).
setopt EXTENDED_GLOB; ls ^*.logsetopt GLOB_DOTS — Include dotfiles in glob matches without explicit dot.
setopt GLOB_DOTS; ls *setopt HIST_IGNORE_DUPS — Do not save duplicate commands in history.
setopt HIST_IGNORE_DUPSsetopt HIST_IGNORE_SPACE — Do not save commands that start with a space.
setopt HIST_IGNORE_SPACE; echo 'secret'setopt APPEND_HISTORY — Append to history file instead of overwriting.
setopt APPEND_HISTORYunsetopt <option> — Disable a shell option.
unsetopt CORRECTPrompt Customization
PROMPT='%n@%m %~ %# ' — Set the left prompt. %n=user, %m=host, %~=directory, %#=privilege.
PROMPT='%n@%m %~ %# 'RPROMPT='%T' — Set the right-side prompt (Zsh exclusive). %T=time.
RPROMPT='%T'%F{color}text%f — Color text in prompt. %F starts color, %f resets.
PROMPT='%F{green}%n%f@%F{blue}%m%f %~ %# '%B text %b — Bold text in prompt.
PROMPT='%B%n%b@%m %~ %# 'autoload -Uz promptinit; promptinit — Load built-in prompt themes system.
autoload -Uz promptinit; promptinit; prompt -lDirectory Stack
pushd <dir> — Change directory and push it onto the stack.
pushd /var/logpopd — Pop directory from stack and change to it.
popddirs -v — Show directory stack with index numbers.
dirs -vcd -<n> — Change to directory at stack position n (Zsh feature).
cd -2setopt AUTO_PUSHD — Automatically push directories onto the stack on cd.
setopt AUTO_PUSHD; cd /tmp; cd /var; dirs -vsetopt PUSHD_IGNORE_DUPS — Do not push duplicate directories onto the stack.
setopt PUSHD_IGNORE_DUPSAliases & Functions
alias name='command' — Create a simple alias.
alias ll='ls -la'alias -g NAME='text' — Create a global alias. Expanded anywhere in the command line.
alias -g G='| grep'; ls G patternalias -s ext=command — Suffix alias. Associates a file extension with a command.
alias -s json=code; ./data.json # opens in VS Codewhich <command> — Show where a command is defined (alias, function, or binary).
which lsfunctions <name> — Display the definition of a function.
functions greetOh My Zsh
plugins=(git docker npm) — Enable plugins in .zshrc. Space-separated list.
plugins=(git docker npm node composer)ZSH_THEME='robbyrussell' — Set the prompt theme in .zshrc.
ZSH_THEME='agnoster'omz update — Update Oh My Zsh to the latest version.
omz updateomz plugin list — List all available Oh My Zsh plugins.
omz plugin listomz theme list — List all available Oh My Zsh themes.
omz theme listConfiguration Files
~/.zshenv — Loaded always (login, interactive, scripts). Use for PATH and exports.
export PATH="$HOME/bin:$PATH"~/.zprofile — Loaded for login shells only. Similar to .bash_profile.
eval "$(brew shellenv)"~/.zshrc — Loaded for interactive shells. Main configuration file.
source ~/.zshrc # reload config~/.zlogin — Loaded after .zshrc for login shells.
# login message~/.zlogout — Loaded when a login shell exits.
# cleanup taskssource ~/.zshrc — Reload Zsh configuration without restarting.
source ~/.zshrcCommon Patterns
zmv 'pattern' 'replacement' — Batch rename files using patterns (load with autoload zmv).
autoload zmv; zmv '(*).txt' '$1.md'ls -la **/*.log(.mw-1) — Find all log files modified in the last week recursively.
ls -la **/*.log(.mw-1)print -l **/*.js — List matching files one per line (cleaner than ls).
print -l **/*.jsecho ${(F)array} — Print array elements one per line (F = join with newlines).
arr=(one two three); echo "${(F)arr}"for f in **/*(.Lm+10); do echo "$f"; done — Find files larger than 10 MB recursively.
for f in **/*(.Lm+10); do echo "$f"; donetake <dir> — Create a directory and cd into it (Oh My Zsh function).
take new-project Conclusion
zsh feels instantly familiar if you come from bash, but rewards you with far more comfort: recursive globbing with qualifiers, flexible parameter expansion, a thoughtful completion system and frameworks like Oh My Zsh save you a lot of typing. Watch out for the small but important differences from bash – above all the 1-based array indexing and the globbing and history behaviour governed by setopt. Keep your customizations in ~/.zshrc, make scripts portable with #!/usr/bin/env zsh, and test changed globbing or correction behaviour once more before relying on it in production scripts.
Further Reading
- zsh manual (zsh.org) – official reference for every option, expansion and glob qualifier
- Oh My Zsh – popular framework with themes, plugins and sensible defaults
- ArchWiki: Zsh – detailed, practical configuration guide