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 **/*.json

ls *(.) — 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 ^*.log

Parameter 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]"  # red

echo "$arr[1]" — Access first element (1-based indexing, unlike Bash).

echo "$colors[2]"  # green

echo "$arr[-1]" — Access last element using negative index.

echo "$colors[-1]"  # blue

echo "$arr[2,4]" — Array slice from index 2 to 4 (inclusive).

nums=(10 20 30 40 50); echo "$nums[2,4]"  # 20 30 40

typeset -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 https

echo "${(kv)map}" — Get all key-value pairs of an associative array.

echo "${(kv)ports}"  # http 80 https 443

History & 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.

!docker

fc — Open last command in $EDITOR for editing and re-execution.

fc

history 1 — Show full command history (Zsh numbers from 1).

history 1 | grep ssh

setopt SHARE_HISTORY — Share history between all running Zsh sessions.

setopt SHARE_HISTORY

Tab Completion

Tab — Complete command, path, or argument. Shows menu on ambiguity.

git che<Tab>  # completes to git checkout

Tab 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 && compinit

zstyle ':completion:*' menu select — Enable interactive menu selection for completions.

zstyle ':completion:*' menu select

zstyle ':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 /tmp

setopt CORRECT — Enable spelling correction for commands.

setopt CORRECT; gti status  # suggests: git?

setopt CORRECT_ALL — Enable spelling correction for commands and arguments.

setopt CORRECT_ALL

setopt NO_CASE_GLOB — Make globbing case-insensitive.

setopt NO_CASE_GLOB; ls *.TXT  # matches .txt too

setopt EXTENDED_GLOB — Enable extended globbing operators (^, ~, #).

setopt EXTENDED_GLOB; ls ^*.log

setopt 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_DUPS

setopt 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_HISTORY

unsetopt <option> — Disable a shell option.

unsetopt CORRECT

Prompt 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 -l

Directory Stack

pushd <dir> — Change directory and push it onto the stack.

pushd /var/log

popd — Pop directory from stack and change to it.

popd

dirs -v — Show directory stack with index numbers.

dirs -v

cd -<n> — Change to directory at stack position n (Zsh feature).

cd -2

setopt AUTO_PUSHD — Automatically push directories onto the stack on cd.

setopt AUTO_PUSHD; cd /tmp; cd /var; dirs -v

setopt PUSHD_IGNORE_DUPS — Do not push duplicate directories onto the stack.

setopt PUSHD_IGNORE_DUPS

Aliases & 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 pattern

alias -s ext=command — Suffix alias. Associates a file extension with a command.

alias -s json=code; ./data.json  # opens in VS Code

which <command> — Show where a command is defined (alias, function, or binary).

which ls

functions <name> — Display the definition of a function.

functions greet

Oh 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 update

omz plugin list — List all available Oh My Zsh plugins.

omz plugin list

omz theme list — List all available Oh My Zsh themes.

omz theme list

Configuration 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 tasks

source ~/.zshrc — Reload Zsh configuration without restarting.

source ~/.zshrc

Common 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 **/*.js

echo ${(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"; done

take <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
  • bash – the GNU Bourne Again Shell, default on most Linux distributions
  • fish – user-friendly shell with autosuggestions out of the box
  • env – display environment variables and run programs in a modified environment