Andrew Mercer
on this page

The Z shell was written by Paul Falstad in 1990. It is the default login shell on macOS (since Catalina) and Kali Linux, and many people use it as their interactive shell on Linux too. It is close enough to bash for day-to-day use, but differs in ways that matter for scripts.

Differences from bash

  • No word splitting of unquoted variables by default. files="a b"; ls $files passes one argument in zsh and two in bash. setopt SH_WORD_SPLIT restores bash behaviour.
  • Arrays start at 1, not 0, unless setopt KSH_ARRAYS is set.
  • Unmatched globs are an error. scp host:*.log . or pip install foo[dev] fails with no matches found, because zsh tries to expand the pattern locally. Quote the argument, or prefix the command with noglob.
  • echo interprets escapes like \n by default, unlike bash.
  • emulate sh (or emulate -L sh inside a function) switches to POSIX-style behaviour. There is no bash emulation, so run bash scripts with bash script.sh rather than sourcing them in zsh.

Features worth knowing

ls **/*.md                     # recursive glob, built in (bash needs shopt -s globstar)
ls *(.)                        # glob qualifiers: regular files only
ls *(/)                        # directories only
ls -l *(.om[1,5])              # the 5 most recently modified files
ls *(.Lm+100)                  # files larger than 100 MB
print -l ${(s/:/)PATH}         # parameter flags: split $PATH on : and print one per line
cd /u/l/b<Tab>                 # completes to /usr/local/bin
take ~/new/dir                 # oh-my-zsh: mkdir -p and cd

Other features: shared history across sessions, spelling correction (setopt CORRECT), right-hand prompts (RPROMPT), the zmv batch renamer (autoload -U zmv; zmv '(*).txt' '$1.md'), and a very capable completion system enabled with autoload -Uz compinit && compinit.

Startup files

File Read by
~/.zshenv every zsh, including scripts; keep it minimal (environment variables only)
~/.zprofile login shells, before .zshrc
~/.zshrc interactive shells; aliases, options, prompt, completion
~/.zlogin login shells, after .zshrc
~/.zlogout login shells on exit

System-wide equivalents live in /etc/zsh/ (Debian) or /etc/ (Fedora, macOS). Set ZDOTDIR in ~/.zshenv to keep the rest under ~/.config/zsh/.

Plain zsh does not save history until you configure it:

HISTFILE=~/.zsh_history
HISTSIZE=50000
SAVEHIST=50000
setopt SHARE_HISTORY HIST_IGNORE_SPACE HIST_IGNORE_ALL_DUPS EXTENDED_HISTORY

Frameworks and plugins

Oh My Zsh is the best known, with hundreds of plugins and themes, but it adds noticeable startup time. Lighter options are Prezto, or a plugin manager such as antidote loading only what you use. Two plugins most people want are zsh-autosuggestions and zsh-syntax-highlighting. Profile startup time with zmodload zsh/zprof at the top of .zshrc and zprof at the bottom.

Further reading