C.W.K.
Stream
Lesson 03 of 10 · published

Why zsh Is the macOS Default

~15 min · zsh, macOS, default-shell, license

Level 0Window Tourist
0 XP0/95 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The license that flipped Apple

Bash 4.0 was released in 2009 under GPLv3. Apple's lawyers do not like GPLv3 (it adds patent and anti-tivoization clauses they read as risky for an OS vendor), so the macOS bash stayed at 3.2 — the last GPLv2 release — for more than a decade. By 2019 that bash was 12 years out of date. macOS Catalina switched the default login shell to zsh, which ships under the permissive MIT-style zsh license, and Apple has been on a current release ever since.

What zsh gives you over bash 3.2

  • Real completion enginecompinit plus thousands of community completion files. Tab on git shows branches, on kubectl shows pods.
  • Recursive globbing**/*.py matches every Python file under the current directory. No find needed for the common case.
  • Glob qualifiers*(.om[1]) means "the most recently modified plain file in this directory." Compact and fast.
  • Themed prompts — Powerlevel10k, Starship, Pure. Git branch, Python venv, Kubernetes context, all in the prompt without scripting.
  • Plugin ecosystems — Oh-My-Zsh, Prezto, zinit. Drop in auto-suggestion, syntax highlighting, history search.

What zsh keeps from bash

Almost all interactive bash habits work — $(...), [[ ]], $?, $0, here-docs, set -e, arrays. The differences only show up in tricky places: word splitting, glob behavior, read flags, array indexing (zsh starts at 1 by default — see the scripting track).

When to script in zsh vs bash

For scripts you keep on your own laptop, zsh is fine. For scripts you ship to servers, container images, CI runners, or other developers' machines, write bash or POSIX sh — bash is on every Linux distro, zsh is not. The shebang decides; the body has to match.

Code

Recursive glob — find every Python file·zsh
# Every .py file under the current tree
ls **/*.py
# Largest 5 .py files (zsh glob qualifiers)
ls -lh -- **/*.py(.OL[1,5])
Tab-completion for git, kubectl, brew·zsh
# Make sure compinit is loaded once per session
autoload -Uz compinit && compinit
# Then this Tab completes branch names
git checkout <Tab>
# This Tab completes pods in your current k8s context
kubectl logs <Tab>

External links

Exercise

Run chsh -s /bin/zsh if you somehow are still on bash. Add autoload -Uz compinit && compinit to your .zshrc. Restart the terminal. Type git checkout followed by Tab — you should now see your branch list. If you do not, run compinit -d to rebuild the cache.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.