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.

Family tree: Bourne sh descends to dash, ash, ksh, zsh and bash; independent shells are csh, fish, PowerShell and cmd
Bourne-family shells speak roughly the same language; independent shells do not.

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:

TargetInterpreterWhy
Portable server scripts#!/bin/sh (POSIX)Runs everywhere, including dash and BusyBox
Feature-rich automation#!/usr/bin/env bashArrays, [[ ]], strict mode
Alpine / containersPOSIX shBash may not be installed
Windows nativePowerShell or WSL Bashcmd.exe cannot express Bash

Throughout this track we write real Bash and mark the places where a POSIX-only script would differ.