Skip to content
C.W.K.
Stream
Lesson 02 of 10 · published

A Brief History: sh → bash → zsh → fish

~15 min · history, sh, bash, zsh, fish, posix

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

Why care about the shell timeline?

You will read scripts written for sh in 1989 alongside zsh config files written last week. Knowing which shell each tool targets keeps you from copying a piece of bash-only syntax into a strict POSIX script and watching it explode in CI.

1979 — Bourne shell (sh)

Stephen Bourne wrote sh at Bell Labs to replace the original Thompson shell. It defined the syntax that everyone else cloned: pipes, if/then/fi, here-docs, environment variables, $?. When you write #!/bin/sh, you are asking for that minimal Bourne-flavored grammar — no arrays, no [[ ]], no fancy expansion.

1989 — Bourne Again (bash)

bash is the GNU project's free Bourne replacement. It absorbed ideas from Korn shell (ksh) and C shell (csh): history, command-line editing, arrays, [[ ]] conditionals, $(...) substitution. macOS used bash as the default from 10.3 (2003) until 10.15 (2019), but Apple froze the version at 3.2 because later releases switched to GPLv3.

1990 — Z shell (zsh)

Paul Falstad wrote zsh to be "bash plus everything good from the others." Better completion, recursive globbing (**), prompt themes, named directories, modular plugins via Oh-My-Zsh / Prezto / zinit. macOS Catalina (2019) made it the default login shell.

2005 — fish

fish ("friendly interactive shell") rejected POSIX compatibility on purpose. It has the smartest defaults of any shell — autosuggestions, syntax highlighting, sane scripting — but you cannot run a bash script verbatim. fish is for the prompt, not for portable scripts.

The rule of thumb

Use zsh (or fish) for your interactive prompt. Use bash or POSIX sh for scripts you ship to other machines. Never assume a script's interpreter — always set the shebang.

Code

What's installed on this Mac?·bash
# All registered login shells
cat /etc/shells
# Where each one lives
for s in sh bash zsh fish; do
  printf '%-5s -> ' "$s"
  command -v "$s" || echo '(not installed)'
done
Pin the interpreter so the script doesn't surprise you·bash
#!/usr/bin/env bash
# Use bash specifically, not whatever sh happens to be linked to
set -euo pipefail
echo "running on $(bash --version | head -1)"

External links

Exercise

Run cat /etc/shells on your Mac. Then command -v bash and bash --version. Confirm bash is 3.2.x. If you want a modern bash, brew install bash and check the new path with command -v bash again — Homebrew puts it under /opt/homebrew/bin/bash while system bash is /bin/bash.

Progress

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

Comments 2

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.
  1. EC
    Erik Choi

    윈도우 환경에서 공부중이라 bash를 다루기 어렵지만, 이번 챕터에서 key point는 내가 작업할 때는 사용이 편한 fish와 같은거를 쓰고, 공유할 때는 범용성이 뛰어난 bash와같은 문법을사용해라.

    즉 사용버전과 배포버전 각각의 환경(나의 환경과 제3자들의환경)이 다름을 인식하라는 것인가요?

    1. Pippa
      Pippa· warmEErik Choi

      네, 거의 정확해요. 조금 더 정확히 말하면 ‘내가 직접 명령을 입력하는 대화형 환경’과 ‘다른 컴퓨터가 실행할 스크립트의 환경’을 분리해서 생각하는 거예요. 전자는 Windows Terminal+PowerShell이나 fish처럼 편한 걸 써도 되지만, 공유하는 스크립트는 대상 컴퓨터에 실제로 설치된 인터프리터를 기준으로 작성하고 shebang이나 실행 명령으로 명시해야 해요. 다만 Windows 대상이라면 무조건 bash가 아니라 PowerShell이 더 범용적일 수도 있어요.