Jul 15, 2022
In the beginning was the command line. Actually, before that were punch cards and paper tape. But at Multics and RSTS and DTSS came out, programmers and users needed a way to interface with the computer through the teletypes and other terminals that appeared in the early age of interactive computing. Those were often just a program that sat on a filesystem eventually as a daemon, listening for input on keyboards. This was one of the first things the team that built Unix needed, once they had a kernel that could compile. And from the very beginning it was independent of the operating system.
Due to the shell's independence from the underlying operating system, numerous shells have been developed during Unix’s history, albeit only a few have attained widespread use. Shells are also referred to as Command-Line Interpreters (or CLIs), processes commands a user sends from a teletype, then a terminal. This provided a simpler interface for common tasks, rather than interfacing with the underlying C programming. Over the years, a number of shells have come and gone. Some of the most basic and original commands came from Multics, but the shell as we know it today was introduced as the Thompson shell in the first versions of Unix.
Ken Thompson introduced the first Unix shell in 1971 with the Thompson Shell, the ancestor of the shell we still find in /bin/sh. The shell ran in the background and allowed for a concise syntax for redirecting the output of commands to one another. For example, pass the output to a file with > or read input from a file with <. We could also pipe output to a second command using a |. This simple structure has persisted into modern shells, even as the kernels and capabilities have become infinitely more complex. The Thompson shell didn’t have options for scripting, as Ken Thompson was more of a C programmer. So future shells would add those options. But when it came to basic operations in Unix, like running commands and viewing their output, he didn’t need to give users more privileged forms of access through the shell.
Others built tools for Unix as well. Bill Joy wrote a different text editor when Berkeley had Thompson out to install Unix on their PDP. And 1977 saw the earliest forms of what we would later call the Bourne Shell, written by Steve Bourne. This shell. The Bourne shell was designed with two key aims: to act as a command interpreter for interactively executing operating system commands and to facilitate scripting. One of the more important aspects of going beyond piping output into other commands and into a more advanced scripting language is the ability to perform conditional if/then statements, loops, and variables. And thus rather than learn C to write simple programmers, generations of engineers and end users could now use basic functional programming at a bourne shell.
Bill Joy created the C shell in 1978 while a graduate student at the University of California, Berkeley. It was designed for Berkeley Software Distribution (BSD) Unix machines. One of the main design goals of the C shell was to build a scripting language that seemed like C. Joy added one of my favorite features of every shell made after that one: command history. I’ve written many shell scripts by just cut-copy-pasting a few commands from my bash history and piping or variabalizing the output. Add to that the ability to use the up or down arrow to re-run previous commands and we got a huge productivity gain for people that did the same tasks, like editing a file. Simply scroll up through previous commands to run the same vi editor. That vi command also shipped first with BSD.
There was another huge time saver out there in another operating system. An operating system called Tenex had name and command completion. The Tenex OS first shipped out of BBN, or Bolt, Beranek, and Newman, for PDPs. Unix had as well and so a number of early users had experience with both. Tenex had command completion, just hit the tab and the command being typed would automatically complete if the text started matched the text of a command in a path for commands. That project was started by Ken Greer at Carnegie Mellon University in 1975 and got merged into the C shell in 1981, adding the t for Tenex to the C for C shell and gave us tcsh. Thus tcsh had backwards compatibility with csh.
David Korn at Bell labs added the korn shell, or ksh in the early 1980s. He added the idea that the user interface could provide a number of editors. For example, use emacs or vi to edit files. He borrowed ideas from the c shell and made minor tweaks that provided outsized impacts to productivity. Even Microsoft added a Korn shell option into Windows NT, as though Dave Cutler was paying homage to another great programmer.
Brian Fox then added on to the Bourne shell with bash. He was working with the Free Software Foundation with Richard Stallman, and they wanted a shell that could do more advanced scripting but whose source code was open source. They started the project in 1988 and shipped bash in 1989. Bash then went on to become the most widely used and distributed shell in the arsenal of the Unix programmer. Bash stands for Bourne Again Shell and so was backwards compatible with bourne shell but also added features from tcsh, korn, and C shell, staying mostly backwards compatible with other shells. Due to the licensing, bash became the de facto standard (and often default shell) for GNU/Linux distributions and serves as the standard interactive shell for users, located at /bin/bash location. Now we had command history, tabbed auto-completion, command-line editing, multiple paths, multiple options for interpreters, a directory stack, full environment variables, and the modern command line environment.
Paul Falstad created the initial version of zsh, or the Z Shell, in 1990. The Z shell (zsh) can be used interactively as a login shell or as more sophisticated command interpreter for shell scripting. As with previous shells, it is an optimized Bourne shell that incorporates several features from bash and tcsh and is mostly backwards compatible. Zsh comes with the tabbed auto-completion, regex integration (in addition to the standard glowing options available since the 1970s, additional shorthand for command scoping, but with a number of security features. The ability to limit memory and privilege escalations became critical in order to keep from having some of the same issues we’ve seen for decades with Windows and other operating systems as they evolved to meet Unix scripting, borrowing many a feature for Powershell from cousins in the Unix and Linux worlds.
These are just the big ones. Sometimes it feels like every developer with a decent grasp of C and a workflow divergent from the norm (which is most developers), has taken a stab at developing their own shell. This is one of the great parts of having access to source code. The options are endless. At this point, we just take these productivity gains for granted. But it was decades of innovative approaches as Unix and then Linux and now MacOS and Android reached out to the rest of the world to change how we work.