The Unix Command Language (1976)
github.com
github.com
PDF: https://susam.github.io/tucl/the-unix-command-language.pdf
HTML: https://susam.github.io/tucl/the-unix-command-language.html
The PDF document is a scanned copy of the first ever paper that was published on the Unix shell. The paper was written by Ken Thompson and published in Structured Programming (Infotech state of the art report).
The scanned copy was first obtained from Ken Thompson by wesleyneo and shared on archive.org. I combined the scanned images into a single PDF document and shared it here. Also, wesleyneo transcribed the paper to text format and I further edited and reformatted it to Markdown format. The HTML document is automatically generated from the Markdown file.
All of these files are shared on the Internet with permission from Ken Thompson.
- "This this invokes" -> "Thus this invokes"
- "the standard output had occurred" -> "the standard output that has occurred"
- "without typing up a console" -> "without tying up a console"
- "The Shell, as command" -> "The Shell, as a command"
- "late a night" -> "late at night"
- "source programs has something" -> "source program has something"
- "which states its contents" -> "which states it contents" [sic]
- "In sincerely" -> "I sincerely"Thank you for proofreading the Markdown document.
Thank you for reporting this error.
"A program is generally exponentially complicated by the number of notions that it invents for itself. To reduce this complication to a minimum, you have to make the number of notions zero or one, which are two numbers that can be raised to any power without disturbing this concept. Since you cannot achieve much with zero notions, it is my belief that you should base systems on a single notion."
Apart from the "goto" command and a different "if" statement syntax, all of the examples would run in a modern Bash shell; not much has changed fundamentally.
There seem to be no comments, and the argument for the no-op ":" is used for this purpose instead.
Using the argument of ":" as the label for the "goto" command reminded me of sed, which does exactly the same (and probably was influenced by it):
sed ': label
s/x/y/
/x/b label'
loops over the "s/x/y/" command until the pattern space doesn't match "/x/" any longer. (Just for illustration - this could be replaced by a single global substitution, of course.)"goto" and labels are also the replacement for all the looping constructs we're used to today.
The differentiation between source/filter/sink types of programs makes so much sense, and while maybe obvious, I've never seen it described this clearly. Descriptions of the composability of Unix programs often focus on the filter aspect of programs.
$ echo 'coffining' | sed ':d s/fin//; td'
cog
$ echo 'coffining' | sed ':d s/fin//; //b d'
cog> Many familiar computing ‘concepts’ are missing from UNIX. Files have no records. There are no access methods. User programs contain no system buffers. There are no file types.
why would you believe that ? maybe computing would be 10x less painful today than it is if these missing concepts had been implemented. Or maybe 10x more.
Current mainframe programming environments retain a lot of this structure. Here's a writeup by someone trained on more Unix-derived environments who was self-teaching on the '60s legacy stuff: https://medium.com/the-technical-archaeologist/hello-world-o...
Coming to Unix from another (larger than a PC) OS was strange because it felt so stripped-down, yet capable, largely because of the extreme power the shell gave you to concatenate functionality. I've never read this particular document, an it does really explain this capability well.
That is not at all obvious. There's a reason SQL is a thing. There's a reason that file name extensions are ubiquitous. There's a reason that security is a hot mess. It turns out that you really do need all these things, and if you don't provide them in the OS, then they will need to be provided at the user level.
I think the big problem with records is that it opens a huge can of worms.
How should we represent dates? Binary data? The type of a binary file? Mime types?
All the answers to these questions should be designed to age gracefully over the next half century or so.
> goto argument
> 'rewinds' its standard input. It then reads the standard input looking for the syntax of a : command with an argument matching it own. It leaves the standard input positioned after the : command. When control is returned to the shell, execution continues where the standard input was positioned. (This implies certain things about file positioning and open file sharing that will not be discussed here.)
Oh man, `:` makes so much sense now. It was originally meant to be like a label.
I’ve always thought that the concept of piping input to output and the shell is on of the most powerful “programming environments” around and to see its origins is humbling!
I distinctly remember encountering exactly this paper, as my first exposure to Unix. It made a deep, deep impression. Pipe composition is just unaccountably powerful.
What might not be so easy for people to understand today is how profoundly shocking it was to see computer commands and results expressed in lower case. I had never seen it done. Ever. It didn't seem possible, at first. After a few seconds, it was obvious, but still oddly liberating. You don't know computers are shouting at you until, suddenly, they aren't.
This is also the same reason that if you try something like the following:
grep whatever somefile >somefile
You always end up with somefile being empty, whereas what you thought you were doing was replacing the contents of the file with only the lines in the file that contain the word “whatever”. But instead the shell will truncate the file first and then grep is searching through an already empty file and therefore there is nothing to find and the file ends up empty. grep string * > out
and wondered why it was taking so long. The shell (probably csh) had created the file "out" before it expanded the *, so my grep command was forever finding "string" in it's own output. It filled the disk before I realized what was happening. I just did a quick test and bash seems to create the output file after doing the globbing, and under tcsh, grep gave a warning that the output file was also an input file and it did not search it. sh >file
be sh <file
?Please see the PDF document at https://susam.github.io/tucl/the-unix-command-language.pdf for a scanned copy of the original paper. If you find an error in the Markdown or HTML transcript, please create an issue or send a pull request to https://github.com/susam/tucl.