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 $filespasses one argument in zsh and two in bash.setopt SH_WORD_SPLITrestores bash behaviour. - Arrays start at 1, not 0, unless
setopt KSH_ARRAYSis set. - Unmatched globs are an error.
scp host:*.log .orpip install foo[dev]fails withno matches found, because zsh tries to expand the pattern locally. Quote the argument, or prefix the command withnoglob. echointerprets escapes like\nby default, unlike bash.emulate sh(oremulate -L shinside a function) switches to POSIX-style behaviour. There is no bash emulation, so run bash scripts withbash script.shrather 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¶
- Zsh manual and the Zsh guide
- bash for comparison