← Back to homeKeyboard Shortcut

Bourne Shell

Ah, the Bourne shell. Or, as some prefer, sh. A foundational piece of the digital bedrock, still stubbornly present in nearly every corner of Unix-like existence. Not because it’s exciting, mind you, but because it’s there. And it works. Mostly. Its ubiquity is less a testament to its charm and more to its sheer, unyielding practicality.


Command-line interpreter for operating systems

Not to be confused with the Bourne-Again Shell, which is less a shell and more an entire existential crisis for your terminal.

Bourne shell

Bourne shell interaction on Version 7 Unix

A rather dated depiction of Bourne shell interaction on Version 7 Unix, likely from a time when blinking cursors were considered cutting-edge.

| Attribute | Detail The Bourne shell ( sh ) is a shell command-line interpreter for computer operating systems. It first appeared on Version 7 Unix, as its default shell. Unix-like systems continue to have /bin/sh —which will be the Bourne shell, or a symbolic link or hard link to a compatible shell—even when other shells are used by most users. This enduring presence of /bin/sh is not merely a historical footnote; it's a critical component of system bootstrapping and the execution of myriad system scripts, ensuring a common, minimal, and predictable environment. Its continued existence underscores a fundamental principle in system design: stability and compatibility often trump novelty.

The Bourne shell was once the undisputed standard on all branded Unix systems, a testament to its robust design and broad adoption. However, a slight divergence existed, as historically BSD-based systems, with their own distinct lineage, frequently employed scripts written in csh. Despite these variations, the Bourne shell's fundamental syntax and operational paradigm became the bedrock for future shell development. As the basis of the POSIX sh syntax, Bourne shell scripts are remarkably portable and can typically be executed without modification using modern, compatible shells such as Bash or dash on contemporary Linux or other Unix-like systems. Indeed, Bash itself, often lauded as the "Bourne-Again Shell," is fundamentally a free clone, an expansive reimagining that builds upon the solid, if somewhat austere, foundation laid by the original Bourne shell.

History

Origins

One might assume innovation springs from genius, but often it’s just someone trying to fix what’s broken. In this case, work on the Bourne shell initially commenced in 1976. Developed by the rather influential Stephen Bourne at the legendary Bell Labs, it was conceived as a much-needed replacement for the preceding Thompson shell. The Thompson shell, while pioneering, suffered from certain limitations that made advanced scripting cumbersome, if not outright impractical. Notably, it lacked proper control flow constructs and a robust variable mechanism, forcing convoluted workarounds for anything beyond simple command sequencing. Bourne's new executable wisely retained the familiar sh filename, a subtle nod to continuity while introducing a paradigm shift in functionality. The Bourne shell also had another predecessor in the form of the Mashey shell, which had introduced some significant scripting features, though it was not as widely adopted or influential in the long run as Bourne's creation.

The Bourne shell made its grand debut in 1979, integrated into the seminal Version 7 Unix release, which was widely distributed to colleges and universities, seeding its influence across academic and research institutions. While it certainly served as an interactive command interpreter—a somewhat gruff but reliable companion for daily terminal jockeying—its true brilliance lay in its design as a sophisticated scripting language. It incorporated nearly all the features now commonly accepted as essential for producing structured programs, a significant leap forward from its predecessors. This deliberate design choice ensured that the shell wasn't just a way to type commands, but a powerful, albeit sometimes cryptic, programming environment in its own right.

Its ascendancy was further solidified and its programming capabilities widely recognized with the publication of the seminal work, "The Unix Programming Environment," authored by the esteemed Brian Kernighan and Rob Pike. This book, which became the first commercially published volume to present the shell explicitly as a programming language in an accessible tutorial format, significantly broadened its appeal and taught an entire generation of programmers how to leverage its power. The book effectively demystified shell scripting, transforming it from an arcane art into a practical skill for anyone navigating the burgeoning Unix landscape.

Primary goals

The goals behind the Bourne shell's design were, ostensibly, noble—or at least, intensely practical. According to Bourne himself, a set of core objectives guided its development:

  • To allow shell scripts to be used effectively as filters. This was a direct embrace of the fundamental Unix philosophy of small, sharp tools that do one thing well and can be chained together. The shell was designed to facilitate this modularity, ensuring that output from one command could seamlessly become input for another.
  • To provide robust programmability, including essential control flow constructs (like conditionals and loops) and flexible variables. This was a critical departure from simpler shells, transforming the shell from a mere command executor into a genuine programming environment capable of handling complex logic and data manipulation.
  • To offer precise control over all input/output file descriptors. This seemingly minor detail was, in fact, a powerful feature, allowing scripts to manage where their data came from, where it went, and crucially, to separate standard output from error messages, a concept that would prove invaluable for robust automation.
  • To enable fine-grained control over signal handling within scripts. This empowered script writers to gracefully manage asynchronous events such as user interruptions (Ctrl+C) or termination signals, allowing for cleaner shutdowns or resource cleanup, rather than abrupt, messy exits.
  • To impose no arbitrary limits on string lengths when interpreting shell scripts. A subtle but crucial point, this ensured that the shell wouldn't bottleneck complex operations or data processing due to internal buffer constraints, a common frustration in earlier systems.
  • To rationalize and generalize the string quoting mechanism. This was a direct response to the often confusing and inconsistent quoting rules of previous shells, aiming for a more predictable and robust way to handle strings containing special characters—a task still debated in hushed, frustrated tones in dark corners of the internet, but undeniably improved by Bourne's efforts.
  • To establish a sophisticated environment mechanism. This allowed contextual information (like paths, user settings, or application-specific configurations) to be established once at startup and then implicitly propagated to sub-scripts and child processes without the clumsy necessity of passing explicit positional parameters for every single piece of information. This elegant solution significantly simplified the creation of complex, interconnected shell programs.

Features of the original version

The Version 7 Unix Bourne shell, despite its age, was remarkably feature-rich for its time, laying down many conventions that persist today. Its capabilities included:

  • Script Invocation: Scripts could be invoked simply by using their filename as a command, treating them as first-class executables. This streamlined automation and made the shell a powerful tool for building custom utilities.
  • Interactive and Non-interactive Modes: The shell was versatile, equally at home when used interactively by a user typing commands at a prompt or when executing predefined sequences of commands within a script, demonstrating its dual nature as both a user interface and a programming language.
  • Synchronous and Asynchronous Execution: It allowed for both synchronous execution, where commands run one after another in sequence, and asynchronous execution, where commands could be run in the background (using the & operator), freeing up the terminal for other tasks. This was a foundational step towards multitasking in an interactive environment.
  • Input/Output Redirection and Pipelines: Core to the Unix philosophy, the shell fully supported redirecting input from files (<) and output to files (>), as well as appending output (>>). More importantly, it introduced robust pipelines (|), allowing the output of one command to be directly fed as input to another, creating powerful data processing chains.
  • Built-in Commands: It provided a set of essential built-in commands for common operations, such as cd for changing directories or exec for replacing the current shell process. These were executed directly by the shell itself, improving efficiency by avoiding the overhead of launching external programs.
  • Flow Control Constructs and Quotation Facilities: The inclusion of if-then-else-fi, case-in-esac, and for-do-done loops brought true programming capabilities to the shell, enabling complex decision-making and iteration. Its robust quotation mechanisms (single quotes, double quotes, backslashes) provided fine-grained control over how strings and special characters were interpreted.
  • Typeless Variables: Variables in the Bourne shell were inherently typeless, meaning they could hold any string value. This offered immense flexibility, though it also meant the programmer bore the responsibility for ensuring data was used in a consistent manner.
  • Local and Global Variable Scope: The shell supported both local variables, which exist only within a specific function or script, and global variables, which are accessible throughout the shell environment and its child processes (especially when exported). This provided a basic, yet effective, mechanism for managing data visibility.
  • No Compilation Requirement: Scripts written for the Bourne shell did not require a separate compilation step; they were interpreted directly at runtime. This "scripting" paradigm offered rapid development cycles and ease of modification, a stark contrast to compiled languages.
  • Absence of goto: Deliberately, the Bourne shell eschewed a goto facility, a controversial feature in many programming languages that often leads to spaghetti code. This enforced a more structured approach to programming, encouraging cleaner and more maintainable scripts.
  • Command substitution: A powerful feature that allowed the output of a command to be used as an argument to another command. This was achieved using backquotes, as in `command`. For instance, echo The date is date`` would execute the date command and embed its output directly into the echo command's argument list.
  • Here documents: Employing the << operator, here documents provided a convenient way to embed a block of multi-line input text directly within a script. This eliminated the need for external temporary files for input data, making scripts more self-contained and readable.
  • Looping Constructs: The shell offered for ~ do ~ done loops for iteration. A particularly common pattern was the use of $* to loop over all positional arguments passed to a script. Additionally, for ~ in ~ do ~ done loops allowed iteration over arbitrary lists of items, providing flexibility for processing collections of data.
  • Selection Mechanism (case): The case ~ in ~ esac selection mechanism provided a structured way to handle multiple conditional branches, primarily intended to assist with argument parsing, allowing scripts to respond differently based on various command-line options.
  • Environment Variables: The sh shell provided robust support for environment variables, utilizing keyword parameters and exportable variables. This allowed for the establishment of a dynamic operating context, where variables like PATH or HOME could influence the behavior of commands and child processes.
  • Strong I/O Control and Expression Matching: Beyond basic redirection, the shell contained strong provisions for fine-grained control over input and output, and in its expression matching facilities, it laid the groundwork for powerful text processing capabilities that would be further expanded in utilities like grep and sed.

The Bourne shell also holds the distinction of being the first to standardize the convention of using file descriptor 2> specifically for error messages. This seemingly minor innovation was, in fact, a stroke of genius, allowing far greater programmatic control during scripting by keeping error messages entirely separate from the standard data output. This clean separation made it much easier to pipe only valid data through a series of commands, while directing errors to a log file or the terminal for user review, significantly enhancing the robustness and reliability of shell scripts.

Stephen Bourne's personal coding style was significantly influenced by his prior experience with the ALGOL 68C compiler, a project he had dedicated considerable effort to at Cambridge University. This influence was not merely superficial; it deeply permeated the design and implementation of the shell. Beyond the general structural style in which the program was written, Bourne consciously reused distinct portions of ALGOL 68's syntax and control structures. This included the if ~ then ~ elif ~ then ~ else ~ fi construct, the case ~ in ~ esac selection mechanism, and the for / while ~ do ~ od looping clauses (with the Bourne shell notably opting for done instead of od). Moreover, and perhaps more controversially for pure C programmers—although the v7 shell is definitively written in C—Bourne took advantage of some rather clever, if occasionally bewildering, macros to imbue the C source code with a distinct ALGOL 68 flavor. These macros, along with the notoriously terse and often cryptic finger command (distributed in Unix version 4.2BSD), served as an unexpected inspiration for the creation of the International Obfuscated C Code Contest (IOCCC). Because, naturally, when you make something functional, someone else will inevitably try to make it utterly unreadable, purely for sport. A truly human endeavor.

Features introduced after 1979

Over the years, the Bourne shell, like any truly useful piece of software, was not left to stagnate. It underwent a series of enhancements and refinements primarily at AT&T, the birthplace of Unix. These various iterations are often informally named after the specific AT&T Unix version they were bundled with, leading to names like Version7, System III, SVR2, SVR3, and SVR4. Identifying a specific "version" of the Bourne shell could be a rather opaque affair, as it was never formally versioned in the way modern software is; instead, its identity was often determined by painstakingly testing for the presence or absence of specific features. This lack of clear versioning is a minor historical annoyance, but it underscores the organic, evolving nature of early Unix development.

Features that gradually found their way into the Bourne shell versions since its original 1979 release include:

  • Built-in test command – Introduced with the System III shell in 1981, this command, often invoked as [ ], provided a standardized and more robust way to perform conditional checks on files, strings, and numerical values, greatly enhancing the power of if statements in scripts.
  • # as comment character – A small but significant quality-of-life improvement, also arriving with the System III shell in 1981. The ability to denote comments with a hash symbol (#) made scripts infinitely more readable and maintainable, allowing programmers to document their intentions or temporarily disable lines of code.
  • Colon in parameter substitutions ${parameter:=word} – This enhancement, part of the System III shell (1981), provided more sophisticated parameter handling. The ${parameter:=word} syntax allowed for default values to be assigned if a variable was unset or null, making scripts more resilient and reducing verbose conditional checks.
  • continue with argument – Another System III shell (1981) addition, continue with an argument allowed a script to skip to the next iteration of an outer loop from within a nested loop, offering finer-grained control over complex looping structures.
  • cat <<-EOF for indented here documents – This subtle but useful feature, introduced in System III shell (1981), allowed the end marker (EOF in this example) for a here document to be indented, and the leading tab characters in the embedded text would be stripped. This made it possible to indent here documents naturally within script code, improving readability without affecting the content.
  • Functions and the return builtin – A major leap forward in structured programming, functions were introduced in the SVR2 shell (1984). This allowed for modular code organization, promoting reusability and making complex scripts far more manageable. The associated return builtin provided a clean way to exit functions and pass back an exit status.
  • Built-ins unset, echo, type – The SVR2 shell (1984) also saw the addition of these essential utilities. unset provided a way to remove variables; echo became a standard way to print output (though its behavior varied across implementations, a minor annoyance); and type helped determine how a command would be interpreted (as a built-in, alias, or external executable).
  • Source code de-ALGOL68-ized – By SVR2 shell (1984), the distinctive ALGOL 68 macros that Stephen Bourne had used to structure the C source code were largely removed or refactored. This move, while perhaps lamentable for those who appreciated the "obfuscated" charm, was a pragmatic decision aimed at making the codebase more accessible and maintainable for a broader range of C programmers who weren't steeped in ALGOL 68.
  • Modern "$@" – The SVR3 shell (1986) introduced a more robust and predictable handling of $@ (all positional parameters). This ensured that when $@ was quoted, each parameter was treated as a distinct word, even if it contained spaces, which was crucial for safely passing arguments to other commands without unintended word splitting.
  • Built-in getopts – Also part of the SVR3 shell (1986), getopts provided a standardized and efficient way to parse command-line options and arguments. This replaced ad-hoc parsing logic, making scripts that accepted options more consistent and easier to write.
  • Cleaned up parameter handling allows recursively callable functions – Further refinements in parameter handling within the SVR3 shell (1986) enabled functions to call themselves recursively. While not a common shell scripting pattern, this demonstrated the increasing sophistication and computational power being embedded directly into the shell.
  • 8-bit clean – The SVR3 shell (1986) became "8-bit clean," meaning it could correctly handle characters that used the full 8 bits of a byte, rather than being limited to 7-bit ASCII. This was an important step towards internationalization and supporting various character sets.
  • Job control – A significant feature for interactive users, job control was introduced in the SVR4 shell (1989). This allowed users to suspend, resume, and move processes between the foreground and background, greatly enhancing the interactive experience and multitasking capabilities of the shell.
  • Multi-byte support – Building on 8-bit cleanliness, the SVR4 shell (1989) also brought multi-byte support. This was crucial for handling character encodings like UTF-8, which represent characters using more than one byte, further solidifying the shell's ability to operate in diverse linguistic environments.

Variants

The core Bourne shell, while influential, was not static. Its design principles and even portions of its source code spawned various derivatives and reimplementations, each addressing specific needs or incorporating new features.

DMERT shell

The Duplex Multi-Environment Real-Time (DMERT) operating system, a hybrid time-sharing and real-time system developed in the 1970s at Bell Labs' Indian Hill location in Naperville, Illinois, notably incorporates a specific, frozen snapshot of the Bourne Shell. This particular version is identified by its internal metadata as "VERSION sys137 DATE 1978 Oct 12 22:39:57," firmly placing it prior to the general release of Version 7 Unix. The DMERT shell is not merely a historical curiosity; it continues to run on specialized 3B21D computers, which are still actively deployed and in use within the telecommunications industry. This enduring presence highlights the remarkable longevity and mission-critical nature of these legacy systems, where stability and proven reliability often take precedence over modern features or frequent updates. It’s a testament to the idea that if it ain't broke, and it's controlling essential infrastructure, you really shouldn't fix it.

Korn shell

Interaction with pdksh in OpenBSD (default shell)

A demonstration of interaction with pdksh within OpenBSD, where it serves as the default shell.

The Korn shell (ksh), meticulously crafted by David Korn and initially based on the original Bourne Shell source code, emerged as a sophisticated "middle road" between the terse utility of the Bourne shell and the more interactive, but often maligned for scripting, C shell. Its syntax was predominantly drawn from the robust and predictable Bourne shell, ensuring compatibility and ease of migration for existing scripts. However, it significantly enhanced the interactive experience by incorporating advanced features, particularly in its job control capabilities, which closely resembled those found in the C shell, but without inheriting the C shell's notorious scripting quirks. The functionality and specific features of the original Korn Shell, often referred to as ksh88 (from the year of its widespread introduction), were so influential that they were ultimately adopted as a foundational basis for the POSIX shell standard, cementing its legacy as a key architectural influence for modern Unix-like systems. A subsequent, more advanced version, ksh93, has been available as open source since 2000 and finds deployment on some Linux distributions. Furthermore, a notable clone of ksh88, known as pdksh (Public Domain Korn Shell), is famously the default shell in OpenBSD, underscoring the enduring appeal and utility of the Korn shell's design.

Schily Bourne Shell

Jörg Schilling's comprehensive collection of system utilities, known as Schily-Tools, includes not one, but three distinct Bourne Shell derivatives. These implementations represent efforts to modernize, enhance, and ensure POSIX compliance for the classic Bourne shell, often incorporating additional features and maintaining the code with a contemporary perspective. Schilling's work often focuses on robustness and adherence to standards, making these derivatives valuable for environments demanding high reliability and precise behavior from their shell.

Relationship to other shells

The Bourne shell did not exist in a vacuum; its design choices and limitations inevitably led to a rich ecosystem of alternative shells, each with its own philosophy and target audience.

C shell

The relationship between the Bourne shell and the C shell (csh) was, to put it mildly, fraught with a certain academic rivalry, igniting what some might call the "shell wars" of the early Unix era. Bill Joy, the principal author of the C shell and a key figure in BSD development, was a vocal critic of the Bourne shell, famously characterizing it as "unfriendly for interactive use." He argued that the C shell, with its C-like syntax, history mechanisms, and alias features, offered a far superior experience for everyday command-line interaction. Stephen Bourne himself, with a weary sigh, probably conceded the point, acknowledging the C shell's advantages for interactive sessions. However, Bourne maintained that his shell was undeniably superior for complex scripting and programming tasks, emphasizing its more robust and predictable control flow, a critical distinction for automation. This sentiment was later echoed and amplified by Tom Christiansen, a prominent Unix and Perl programmer, who famously penned the essay "Csh Programming Considered Harmful," unequivocally criticizing the C shell as being fundamentally unsuitable for serious scripting and programming due to its numerous quirks, inconsistent error handling, and problematic quoting rules. It seems some tools are designed for comfort, others for actual utility. Guess which one stuck around for the heavy lifting?

Almquist shells

A pivotal development in the shell landscape arose from the thorny issue of software licensing and copyright. Specifically, due to lingering copyright concerns surrounding the original Bourne Shell as it was integrated and distributed within historic CSRG BSD releases, a pressing need for a fully open-source alternative emerged. In response to this, Kenneth Almquist meticulously developed a clean-room clone of the Bourne Shell, which came to be known colloquially as the Almquist shell (ash). This highly compatible reimplementation was made available under the permissive BSD license, effectively sidestepping the copyright entanglements of its predecessor.

The Almquist shell rapidly gained traction and remains in active use today on various BSD descendants, particularly in scenarios where a minimal memory footprint and rapid execution are paramount, such as within embedded systems or during the early stages of system booting. The Almquist shell's influence further expanded when it was ported to Linux environments. In this context, the port was subsequently renamed the Debian Almquist shell, or dash. This shell has become a standard component in many Linux distributions, often serving as the default /bin/sh for system scripts. dash distinguishes itself by offering significantly faster execution of standard sh (and POSIX-standard sh in its modern descendants) scripts, coupled with a remarkably smaller memory footprint compared to more feature-laden shells like Bash. Its widespread adoption in this role has had a beneficial side effect: it tends to mercilessly expose "bashisms" – those non-standard, Bash-specific assumptions and extensions inadvertently introduced into scripts that were ostensibly meant to run on any standard sh-compatible shell. This effectively forces script authors to adhere more closely to the POSIX standard, promoting greater portability and robustness across Unix-like systems.

Other shells

The legacy of the Bourne shell extends far and wide, influencing a multitude of other shells that have since emerged:

  • Bash (the Bourne-Again shell), developed in 1989 for the GNU project, is arguably the most widely used shell today. It masterfully incorporates the robust scripting capabilities of the Bourne shell, while adding desirable interactive features from the C shell and advanced programming constructs from the Korn shell. It is conscientiously designed to be POSIX-compliant, ensuring a high degree of compatibility with existing Bourne shell scripts, while simultaneously offering a wealth of extensions and conveniences that have endeared it to generations of users and developers.
  • rc was conceived at Bell Labs by the minimalist Tom Duff as a direct replacement for sh specifically for Version 10 Unix. It champions a simpler, more elegant syntax inspired by ALGOL 68, eschewing some of the complexities of the Bourne shell. rc is famously the default shell for Plan 9 from Bell Labs, a research operating system that offered a fresh perspective on Unix principles. It has also been ported to UNIX as part of Plan 9 from User Space, allowing its unique charm to be experienced on conventional Unix-like systems.
  • Z shell (zsh), developed by Paul Falstad in 1990, stands as an extended and highly customizable Bourne shell. It builds upon the solid foundation of sh while integrating a vast number of improvements and features. These include sophisticated command-line editing, advanced globbing), and a powerful theme engine. It draws inspiration from and incorporates features found in Bash, ksh, and tcsh, effectively aiming to be the "best of all worlds" for users seeking both power and flexibility in their interactive shell environment.

See also

For those with an insatiable curiosity about the myriad ways one can interact with a computer via text, or perhaps a morbid fascination with the evolutionary dead ends of software design: