POSIX Shell
The standardized command-and-scripting language defined by the POSIX Shell and Utilities specification — a portable subset of the Bourne and Korn shells that runs essentially unchanged across Unix, Linux, BSD, and macOS.
Created by IEEE / The Open Group (Austin Group); the shell language is derived from Stephen Bourne's Bourne shell and David Korn's KornShell
POSIX Shell is not a single program but a specification: the Shell Command Language defined in the POSIX Shell and Utilities standard. It describes a portable command interpreter and scripting language — the syntax, built-in commands, expansions, and control structures that any conforming Unix-like shell must support. When a script begins with #!/bin/sh and restricts itself to features in the standard, it should run essentially unchanged across Linux, the BSDs, macOS, Solaris, AIX, and embedded systems, regardless of which actual shell binary is providing sh. In that sense, “POSIX shell” is the common language that the many real shells — dash, ash, ksh, bash in its POSIX mode, and others — agree to speak.
History & Origins
The story of the POSIX shell begins with two earlier shells. In 1979, Stephen Bourne released the Bourne shell (sh) with Version 7 Unix; it introduced the control-flow syntax — if/then/fi, for/do/done, case/esac — that still defines shell scripting today. A few years later, in 1983, David Korn at Bell Labs built the KornShell (ksh), a backward-compatible superset that added command-line editing, functions, and other improvements. Its widely distributed ksh88 release became the most influential interactive and scripting shell of its era.
By the late 1980s the proliferation of competing Unix variants made portability a serious problem, and the IEEE launched the POSIX (Portable Operating System Interface) effort to standardize Unix-like systems. The first POSIX document, IEEE Std 1003.1-1988, covered base operating-system services — processes, files, and I/O — but not the shell.
A note on dates. This page uses 1992 as the first-appearance year for the POSIX shell — the year the Shell Command Language was standardized in IEEE Std 1003.2-1992 (POSIX.2), reportedly ratified in September 1992 after a multi-year effort. The broader POSIX program began earlier: the first POSIX standard, IEEE Std 1003.1-1988 (POSIX.1) in 1988, defined base operating-system services but did not define the shell.
The committee chose ksh88 as the primary basis for the standardized shell, selecting a subset of its features while keeping the result compatible with the older Bourne shell. The result was a carefully specified least common denominator: powerful enough for real scripting, restrained enough that many independent implementations could conform. In 1993 the same shell specification was adopted internationally as ISO/IEC 9945-2.
Design Philosophy
The guiding principle of the POSIX shell is portability over features. Rather than describe one canonical implementation, the standard defines a contract: a set of behaviors that conforming shells must provide and that script authors can rely on. This deliberately excludes many convenient extensions found in individual shells — bash arrays, [[ ... ]] test expressions, local variables, process substitution, and the function keyword are all outside the standard — precisely so that a POSIX script does not become dependent on any single shell.
A few characteristics follow from this philosophy:
- Everything is text. Shell variables are untyped strings; structure comes from word splitting, globbing, and command substitution rather than from a type system.
- The shell is glue. Its job is to launch and connect programs via pipelines, redirection, and exit statuses — not to be a general-purpose computation engine.
- Conformance is testable. Because the language is specified rather than implemented, multiple shells can claim POSIX conformance and be checked against the same document.
Key Features
The POSIX Shell Command Language standardizes the constructs most scripts actually need:
| Feature | Example |
|---|---|
| Variables & assignment | name=value (no spaces around =) |
| Parameter expansion | ${var}, ${var:-default}, ${var%suffix}, ${#var} |
| Command substitution | result=$(command) (the $(...) form is preferred over backticks) |
| Conditionals | if/elif/else/fi, plus the test / [ ... ] utility |
| Loops | for, while, until, with break and continue |
| Case selection | case "$x" in pattern) ... ;; esac |
| Functions | name() { ...; } |
| Arithmetic | $(( expr )) for integer arithmetic |
| Pipelines & redirection | `cmd1 |
A small but complete example:
| |
Notably, the standard does not dictate which utilities exist beyond a core set, but it does specify the behavior of many of them (cd, echo, printf, read, test, expr, and others), which is why portable scripts can rely on them being present and behaving consistently.
Implementations
Because POSIX shell is a specification, it is realized by many distinct programs:
- dash — the Debian Almquist shell, a small and fast POSIX-conformant shell used as
/bin/shon Debian and Ubuntu, prized for speed in system scripts. - ash / BusyBox ash — the lightweight Almquist-shell lineage, ubiquitous in embedded systems and minimal container images.
- ksh — the KornShell, the language’s chief ancestor, which remains broadly POSIX-conformant.
- bash — primarily a superset with many extensions, but it offers a
--posixmode (and behaves more conservatively when invoked assh) to align with the standard. - mksh, yash, and others — additional shells that aim for POSIX conformance with varying extensions.
This many-implementations reality is exactly why writing to the POSIX subset matters: a feature that works in bash may fail under dash, so disciplined scripts target the standard rather than a favorite shell.
Evolution
After the original 1992 shell standard, the maintenance model changed significantly. In 1998 the Austin Group — a joint working group of the IEEE, The Open Group, and ISO/IEC — was formed to unify the previously separate POSIX and Single UNIX Specification documents. The first fruit of that collaboration, POSIX:2001 (Issue 6), merged the former POSIX.1 (system interfaces) and POSIX.2 (shell and utilities) into a single combined specification. Subsequent revisions followed: IEEE Std 1003.1-2008 (Issue 7), a technical-corrigenda rollup as 1003.1-2017, and most recently IEEE Std 1003.1-2024 (Issue 8), published on 14 June 2024 as the first major revision in over fifteen years. Each edition refines the Shell and Utilities volume, but the core shell language has remained remarkably stable — a deliberate consequence of its portability mission.
Current Relevance
The POSIX shell is one of the most quietly pervasive languages in computing. Every time a Linux system boots, installs a package, runs a CI pipeline step, or executes a ./configure script, POSIX-style shell scripting is very likely involved. Its restraint is its strength: by targeting the standardized subset, authors of init scripts, container entrypoints, installers, and cross-platform tooling get a single script that behaves the same on Debian, Alpine, FreeBSD, and macOS alike. Tools such as the checkbashisms utility and shellcheck’s POSIX mode exist specifically to help developers stay within the standard.
Why It Matters
The POSIX shell demonstrates a powerful idea: that a language can be defined by a specification and a conformance contract rather than by a single reference implementation, and that doing so can make it more — not less — durable. By distilling the Bourne and Korn shells into a portable common core, POSIX turned shell scripting from a per-vendor gamble into a reliable lingua franca for automating Unix-like systems. Decades after its 1992 standardization, that common language still underpins the boot sequences, build systems, and glue scripts that hold modern computing together.
Timeline
Notable Uses & Legacy
Debian and Ubuntu (dash as /bin/sh)
Debian and Ubuntu link /bin/sh to dash (the Debian Almquist shell), a small, fast, POSIX-conformant shell. System and package-maintainer scripts that begin with #!/bin/sh are expected to be POSIX shell, which keeps boot-time and installation scripting fast and portable.
Autoconf and configure scripts
The GNU Autoconf build system generates portable ./configure scripts written in POSIX shell so that software can be configured and built on a vast range of Unix-like systems without assuming any particular shell implementation.
BusyBox and embedded systems
BusyBox bundles a compact, largely POSIX-compatible ash shell into a single small binary, making it the standard scripting environment for routers, embedded Linux, container base images, and other space-constrained systems.
System init and service scripts
Traditional System V init scripts, container entrypoints, and CI/CD pipeline steps are frequently written in POSIX sh to guarantee they run identically across Linux distributions, the BSDs, and macOS without depending on bash-specific features.
Cross-platform developer tooling
Installer scripts, Git hooks, and bootstrap scripts (the kind piped from a URL into sh) are commonly written to the POSIX shell subset so a single script works on macOS, Linux, and BSD regardless of which shell is installed.
Language Influence
Influenced By
Influenced
Running Today
Run examples using the official Docker image:
docker pull busybox:latestExample usage:
docker run --rm -v $(pwd):/app -w /app busybox:latest sh script.sh