# 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.

Source: https://www.jpkc.com/db/en/cheatsheets/shell-system/zsh/

<!-- PROSE:intro -->
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.
<!-- PROSE:intro:end -->

## Globbing & Pattern Matching

`ls **/*.txt` — Recursive globbing. Match files in all subdirectories (enabled by default).

```bash
ls **/*.json
```

`ls *(.)` — Glob qualifier: match only regular files.

```bash
ls -la *(.) 
```

`ls *(/)` — Glob qualifier: match only directories.

```bash
ls -d *(/)
```

`ls *(@)` — Glob qualifier: match only symbolic links.

```bash
ls -la *(@)
```

`ls *(om[1,5])` — Glob qualifier: 5 most recently modified files. o=order, m=mtime.

```bash
ls -la *(om[1,5])
```

`ls *(Lk+100)` — Glob qualifier: files larger than 100 KB. L=size, k=KB, +=greater.

```bash
ls -lh *(Lk+100)
```

`ls *(.mh-1)` — Glob qualifier: files modified in the last hour. m=mtime, h=hours.

```bash
ls -la *(.mh-1)
```

`ls (#i)pattern` — Case-insensitive glob matching (requires EXTENDED_GLOB).

```bash
setopt EXTENDED_GLOB; ls (#i)readme*
```

`ls ^pattern` — Negation glob. Match everything except pattern (requires EXTENDED_GLOB).

```bash
setopt EXTENDED_GLOB; ls ^*.log
```

## Parameter Expansion

`${(U)VAR}` — Convert string to uppercase.

```bash
name='hello'; echo "${(U)name}"  # HELLO
```

`${(L)VAR}` — Convert string to lowercase.

```bash
NAME='WORLD'; echo "${(L)NAME}"  # world
```

`${(C)VAR}` — Capitalize first letter of each word.

```bash
str='hello world'; echo "${(C)str}"  # Hello World
```

`${(s:sep:)VAR}` — Split string into an array by separator.

```bash
PATH_PARTS=(${(s/:/)PATH}); echo "${PATH_PARTS[1]}"
```

`${(j:sep:)ARRAY}` — Join array elements with separator.

```bash
arr=(a b c); echo "${(j:,:)arr}"  # a,b,c
```

`${(t)VAR}` — Show the type of a variable (scalar, array, integer, etc.).

```bash
arr=(1 2 3); echo "${(t)arr}"  # array
```

`${(u)ARRAY}` — Remove duplicate elements from an array (unique).

```bash
arr=(a b a c b); echo "${(u)arr}"  # a b c
```

`${(o)ARRAY} / ${(O)ARRAY}` — Sort array in ascending / descending order.

```bash
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).

```bash
colors=(red green blue); echo "$colors[1]"  # red
```

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

```bash
echo "$colors[2]"  # green
```

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

```bash
echo "$colors[-1]"  # blue
```

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

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

`typeset -A map` — Declare an associative array.

```bash
typeset -A ports; ports=(http 80 https 443)
```

`echo "${(k)map}"` — Get all keys of an associative array.

```bash
echo "${(k)ports}"  # http https
```

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

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

## History & Navigation

`Ctrl+R` — Incremental reverse history search.

```bash
Ctrl+R, then type to search
```

`!!` — Repeat the last command.

```bash
sudo !!
```

`!$` — Last argument of the previous command.

```bash
mkdir mydir; cd !$
```

`!*` — All arguments of the previous command.

```bash
echo foo bar baz; echo !*
```

`!<string>` — Run the most recent command starting with string.

```bash
!docker
```

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

```bash
fc
```

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

```bash
history 1 | grep ssh
```

`setopt SHARE_HISTORY` — Share history between all running Zsh sessions.

```bash
setopt SHARE_HISTORY
```

## Tab Completion

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

```bash
git che<Tab>  # completes to git checkout
```

`Tab Tab` — Cycle through completion options in menu.

```bash
cd /u<Tab><Tab>  # cycles through /usr, /Users, etc.
```

`compinit` — Initialize the completion system. Usually in .zshrc.

```bash
autoload -Uz compinit && compinit
```

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

```bash
zstyle ':completion:*' menu select
```

`zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'` — Enable case-insensitive tab completion.

```bash
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).

```bash
setopt AUTO_CD; /tmp  # same as cd /tmp
```

`setopt CORRECT` — Enable spelling correction for commands.

```bash
setopt CORRECT; gti status  # suggests: git?
```

`setopt CORRECT_ALL` — Enable spelling correction for commands and arguments.

```bash
setopt CORRECT_ALL
```

`setopt NO_CASE_GLOB` — Make globbing case-insensitive.

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

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

```bash
setopt EXTENDED_GLOB; ls ^*.log
```

`setopt GLOB_DOTS` — Include dotfiles in glob matches without explicit dot.

```bash
setopt GLOB_DOTS; ls *
```

`setopt HIST_IGNORE_DUPS` — Do not save duplicate commands in history.

```bash
setopt HIST_IGNORE_DUPS
```

`setopt HIST_IGNORE_SPACE` — Do not save commands that start with a space.

```bash
setopt HIST_IGNORE_SPACE; echo 'secret'
```

`setopt APPEND_HISTORY` — Append to history file instead of overwriting.

```bash
setopt APPEND_HISTORY
```

`unsetopt <option>` — Disable a shell option.

```bash
unsetopt CORRECT
```

## Prompt Customization

`PROMPT='%n@%m %~ %# '` — Set the left prompt. %n=user, %m=host, %~=directory, %#=privilege.

```bash
PROMPT='%n@%m %~ %# '
```

`RPROMPT='%T'` — Set the right-side prompt (Zsh exclusive). %T=time.

```bash
RPROMPT='%T'
```

`%F{color}text%f` — Color text in prompt. %F starts color, %f resets.

```bash
PROMPT='%F{green}%n%f@%F{blue}%m%f %~ %# '
```

`%B text %b` — Bold text in prompt.

```bash
PROMPT='%B%n%b@%m %~ %# '
```

`autoload -Uz promptinit; promptinit` — Load built-in prompt themes system.

```bash
autoload -Uz promptinit; promptinit; prompt -l
```

## Directory Stack

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

```bash
pushd /var/log
```

`popd` — Pop directory from stack and change to it.

```bash
popd
```

`dirs -v` — Show directory stack with index numbers.

```bash
dirs -v
```

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

```bash
cd -2
```

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

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

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

```bash
setopt PUSHD_IGNORE_DUPS
```

## Aliases & Functions

`alias name='command'` — Create a simple alias.

```bash
alias ll='ls -la'
```

`alias -g NAME='text'` — Create a global alias. Expanded anywhere in the command line.

```bash
alias -g G='| grep'; ls G pattern
```

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

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

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

```bash
which ls
```

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

```bash
functions greet
```

## Oh My Zsh

`plugins=(git docker npm)` — Enable plugins in .zshrc. Space-separated list.

```bash
plugins=(git docker npm node composer)
```

`ZSH_THEME='robbyrussell'` — Set the prompt theme in .zshrc.

```bash
ZSH_THEME='agnoster'
```

`omz update` — Update Oh My Zsh to the latest version.

```bash
omz update
```

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

```bash
omz plugin list
```

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

```bash
omz theme list
```

## Configuration Files

`~/.zshenv` — Loaded always (login, interactive, scripts). Use for PATH and exports.

```bash
export PATH="$HOME/bin:$PATH"
```

`~/.zprofile` — Loaded for login shells only. Similar to .bash_profile.

```bash
eval "$(brew shellenv)"
```

`~/.zshrc` — Loaded for interactive shells. Main configuration file.

```bash
source ~/.zshrc  # reload config
```

`~/.zlogin` — Loaded after .zshrc for login shells.

```bash
# login message
```

`~/.zlogout` — Loaded when a login shell exits.

```bash
# cleanup tasks
```

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

```bash
source ~/.zshrc
```

## Common Patterns

`zmv 'pattern' 'replacement'` — Batch rename files using patterns (load with autoload zmv).

```bash
autoload zmv; zmv '(*).txt' '$1.md'
```

`ls -la **/*.log(.mw-1)` — Find all log files modified in the last week recursively.

```bash
ls -la **/*.log(.mw-1)
```

`print -l **/*.js` — List matching files one per line (cleaner than ls).

```bash
print -l **/*.js
```

`echo ${(F)array}` — Print array elements one per line (F = join with newlines).

```bash
arr=(one two three); echo "${(F)arr}"
```

`for f in **/*(.Lm+10); do echo "$f"; done` — Find files larger than 10 MB recursively.

```bash
for f in **/*(.Lm+10); do echo "$f"; done
```

`take <dir>` — Create a directory and cd into it (Oh My Zsh function).

```bash
take new-project
```

<!-- PROSE:outro -->
## 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)](https://zsh.sourceforge.io/Doc/) – official reference for every option, expansion and glob qualifier
- [Oh My Zsh](https://ohmyz.sh/) – popular framework with themes, plugins and sensible defaults
- [ArchWiki: Zsh](https://wiki.archlinux.org/title/Zsh) – detailed, practical configuration guide
<!-- PROSE:outro:end -->

## Related Commands

- [bash](https://www.jpkc.com/db/en/cheatsheets/shell-system/bash/) – the GNU Bourne Again Shell, default on most Linux distributions
- [fish](https://www.jpkc.com/db/en/cheatsheets/shell-system/fish/) – user-friendly shell with autosuggestions out of the box
- [env](https://www.jpkc.com/db/en/cheatsheets/shell-system/env/) – display environment variables and run programs in a modified environment

