Est. 1992 Intermediate

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

Paradigm Procedural, Imperative, Scripting
Typing Untyped / string-based (weak, dynamic); arithmetic context is integer
First Appeared 1992 (IEEE Std 1003.2-1992, the Shell and Utilities standard)
Latest Version POSIX.1-2024 / Base Specifications Issue 8 (June 2024)

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:

FeatureExample
Variables & assignmentname=value (no spaces around =)
Parameter expansion${var}, ${var:-default}, ${var%suffix}, ${#var}
Command substitutionresult=$(command) (the $(...) form is preferred over backticks)
Conditionalsif/elif/else/fi, plus the test / [ ... ] utility
Loopsfor, while, until, with break and continue
Case selectioncase "$x" in pattern) ... ;; esac
Functionsname() { ...; }
Arithmetic$(( expr )) for integer arithmetic
Pipelines & redirection`cmd1

A small but complete example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/sh
# Count regular files in the directory given as $1 (default: current dir)
dir=${1:-.}
count=0
for entry in "$dir"/*; do
    if [ -f "$entry" ]; then
        count=$((count + 1))
    fi
done
printf '%s contains %d file(s)\n' "$dir" "$count"

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/sh on 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 --posix mode (and behaves more conservatively when invoked as sh) 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

1979
The Bourne shell (sh), written by Stephen Bourne at Bell Labs, is distributed with Version 7 Unix. It becomes the de facto scripting shell and the direct ancestor of the POSIX shell command language.
1983
David Korn at Bell Labs develops the KornShell (ksh), a backward-compatible superset of the Bourne shell. Its widely distributed ksh88 version (released 1988) later serves as the primary basis for the POSIX shell specification.
1988
IEEE Std 1003.1-1988 (POSIX.1) is published as the first POSIX standard, defining base operating-system services. It does not yet cover the shell; the Shell Command Language is standardized separately four years later.
1992
IEEE Std 1003.2-1992 (POSIX.2), the Shell and Utilities standard, is reportedly ratified in September 1992 after a multi-year effort. It formally defines the POSIX Shell Command Language as a portable subset built largely on ksh88 and compatible with the Bourne shell.
1993
The shell specification is adopted internationally as ISO/IEC 9945-2:1993, giving the POSIX shell command language ISO standing alongside its IEEE designation.
1998
The Austin Group is formed as a joint IEEE / The Open Group / ISO working group to develop and maintain a single, unified specification combining POSIX and the Single UNIX Specification.
2001
IEEE Std 1003.1-2001 (POSIX:2001, Base Specifications Issue 6) merges the former POSIX.1 and POSIX.2 documents into one specification, also forming the core of the Single UNIX Specification Version 3.
2008
IEEE Std 1003.1-2008 (Issue 7) is published, the basis of the Single UNIX Specification Version 4; it is later rolled up with technical corrigenda as IEEE Std 1003.1-2017.
2024
IEEE Std 1003.1-2024 (Base Specifications Issue 8) is published on 14 June 2024 — the first major revision since 2008 — refreshing the Shell and Utilities volume and forming the core of the Single UNIX Specification Version 5.

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

Bourne shell KornShell

Influenced

dash mksh BusyBox ash

Running Today

Run examples using the official Docker image:

docker pull busybox:latest

Example usage:

docker run --rm -v $(pwd):/app -w /app busybox:latest sh script.sh
Last updated: