Shell Interpreters Compared
What an Interpreter Does
A shell is a command interpreter. It does not compile your file to machine code like a C compiler. Instead it reads the script, expands it, and asks the kernel to run programs, one command at a time. That makes shell scripts portable and instant to run, but also slow and fragile if written carelessly.
Every shell answers the same three questions differently: how do I name a variable, how do I test a condition, and what do I do with unquoted whitespace? Those three answers separate the families.
The Bourne Family
In 1979 Stephen Bourne wrote sh at Bell Labs. Its descendants dominate Unix. If a shell is "POSIX-compatible" it means it implements the language that sh defined and that the POSIX standard fixed in writing.
sh — the Standard
sh is a specification more than one program. On modern systems /bin/sh is almost always a symlink or another shell started in POSIX mode. Write to the POSIX subset and your script runs on a server, a container, and a router.
dash — the Fast Minimal Shell
On Debian and Ubuntu, /bin/sh points to dash because it starts several times faster than Bash. Use it for boot scripts and containers; do not expect arrays, [[ ]], or local to work.
bash — the Bourne Again SHell
Bash (1989, Brian Fox, GNU) is a superset of POSIX sh: it adds arrays, associative arrays, [[ ]], process substitution, brace expansion, and more. It is the default login shell on most Linux distributions and the language of this track. Bash runs your script in one of two modes: POSIX (--posix) or its own extended mode.
# Detect which interpreter is really running
echo "$BASH_VERSION" # e.g. 5.2.21(1)-release — empty if not Bash
[ -n "$BASH_VERSION" ] && echo "this is bash"
bash --posix script.sh # run a script in POSIX mode
Other Families
ash — Embedded Linux
ash is the tiny shell behind BusyBox, found on routers, cameras, and Alpine Linux containers. It implements the POSIX subset plus a few extensions. If your script must run inside docker run alpine, treat it as strict POSIX.
ksh — the KornShell
David Korn's ksh (1983) influenced every modern shell: it introduced arithmetic, [[ ]], and coprocesses that Bash later borrowed. It is still common in commercial Unix.
zsh — the Interactive Favourite
zsh is the default shell on macOS. It is a superset of Bash-like syntax with powerful globbing and prompt features, popularised by the Oh-My-Zsh framework. Interactive comforts do not transfer: a script written for Bash may not run under zsh and vice versa.
fish — the Friendly Shell
fish deliberately breaks compatibility for usability: it has no $var=value assignment and richer autosuggestions. Excellent at the prompt, a poor choice as a scripting target if you value portability.
Windows Shells
cmd.exe
The classic Windows command processor uses a completely different language (%VAR%, set, if errorlevel). It is not part of the Bourne family and cannot run Bash scripts.
PowerShell
PowerShell passes objects, not text, between commands, and uses the verb-noun naming style (Get-ChildItem). It is powerful on Windows but incompatible with Bash; cross-platform automation therefore standardises on Bash.
Choosing a Shell
Choose by where the script runs, not by personal taste:
| Target | Interpreter | Why |
|---|---|---|
| Portable server scripts | #!/bin/sh (POSIX) | Runs everywhere, including dash and BusyBox |
| Feature-rich automation | #!/usr/bin/env bash | Arrays, [[ ]], strict mode |
| Alpine / containers | POSIX sh | Bash may not be installed |
| Windows native | PowerShell or WSL Bash | cmd.exe cannot express Bash |
Throughout this track we write real Bash and mark the places where a POSIX-only script would differ.