CTSS RUNCOM: Parameterized Command Chains on a Time-Sharing System
Examine CTSS RUNCOM's command-file contract: CHAIN substitution, left-truncated six-character arguments, comment markers, and supervisor-level execution.
Repeating a build or translation sequence on a shared computer meant re-entering the same commands and file names. MIT’s Compatible Time-Sharing System (CTSS) documented a small tool for that work: RUNCOM, a macro-command that linked public or private commands into a chain and accepted arguments when the user invoked it. Its technical interest is in a small, explicit command-file contract, not a claim that it was the first script or a modern shell in disguise.
This account follows the CTSS Programmer’s Guide sections AH.10.01, AG.8.02, and AG.8.03. The RUNCOM section bears a 12/69 date stamp in the scanned loose-leaf guide; the stamp alone does not establish a formal revision date. The MIT archive identifies the guide as a second edition, while the section itself is the direct evidence for the command contract described here. CTSS Technical Notes describe the system as an IBM 7094 installation with an interval timer, memory-protection and relocation registers, and a 7750 communications channel for teletypewriter consoles. That is the setting for an interactive command facility: a user at a terminal, a supervisor coordinating commands, and a sequence prepared in a file.
A command file with an explicit binding step
The guide calls RUNCOM and CHAIN a “Macro Command.” A macro-command file had to be a BCD line-marked or line-numbered file with one command on each line. Blank lines were ignored. The stated purpose was practical: connect commands so a user could issue one command instead of typing a repeated series again.
CHAIN was the binding declaration. It listed dummy symbols before the first executable command. At execution time, the user could supply actual values, command names, or other arguments; occurrences of the declared symbols in later command lines were replaced from that argument list. The guide’s own example starts with CHAIN ALPH BET TRANSL, then uses those names in ED, PRINTF, TRANSL, and LOAD lines. In other words, the macro could represent a repeatable editing, translation, and loading procedure without hard-coding every input name into each command line.
The boundary rules are unusually concrete and matter to any faithful reconstruction:
- Command arguments were separated by one or more spaces. The documented syntax is therefore whitespace-oriented; the cited section does not describe modern shell quoting or escaping rules.
- An argument longer than six characters was truncated from the left. Under that rule, a seven-character token such as
ARCHIVEbecomesRCHIVE. This is not cosmetic: a tool that silently modernizes or preserves the long name would no longer reproduce the documented interface. - If a macro used dummy symbols, its
CHAINdeclaration had to appear before the first executable command. The guide allows command names and actual values in addition to dummy symbols, but it does not make every word a variable by default. - Blank lines were skipped. Each remaining line supplied a command in the chain.
- AH.10.01 p.2 defines two substitution sentinels.
(NIL)causes the corresponding dummy argument to be ignored; if it replaces a command name, that entire command is ignored.(END)is replaced by a fence, and when used as a command name it terminates the chain. Extra arguments are ignored by commands receiving the substitution; if fewer arguments are supplied thanCHAINdeclares, the rightmost dummy symbols retain their literal names.
This was parameter substitution in a command sequence, not evidence of a general expression language. The command file described in the guide supplies the sequence and named slots; it does not document arithmetic, arbitrary branching, a pipeline grammar, or a full interactive language. That distinction keeps the historical description within the source record.
Comments could be silent or visible
The first character of a comment line selected its behavior. Lines beginning with * were ignored during execution. Lines beginning with $ were printed on the user’s console at the point where they occurred in the chain. A macro author could therefore leave a private note out of execution or include a visible progress message among the commands.
Those rules are operational semantics, not merely editorial conventions. If a reader is implementing a parser or recreating a command sequence, treating both markers alike changes what the user sees. The manual does not describe a general comment escape mechanism; the relevant test is the first character of the line, exactly as the guide specifies.
RUNCOM was one path into the supervisor’s command chain
The guide describes more than one program-level path, and they should not be collapsed into one interface. Section AG.8.02 says SCHAIN is the callable equivalent of RUNCOM: a MAD, FORTRAN, or FAP program can name a BCD file and pass arguments, and the guide allows a chain of any length, including nested or recursive RUNCOM specifications. Section AG.8.03 describes lower-level control through CHNCOM, CLS, and CLC: a program builds a fenced vector of command names and arguments, and each command in that list must call CHNCOM to start the next one. That separately constructed list is limited to five commands, with each fenced command buffer limited to 20 words. Near the end-of-chain discussion, the searchable text for AG.8.03 p.1 renders a term as DCMNT (the scanned lettering is difficult to distinguish), while p.4 explicitly specifies DORMNT when j=1 (a core image is available) and DEAD when j=0. Treat this as a spelling or scan/transcription discrepancy, not evidence of a contradictory runtime contract; p.4 supplies the explicit state-dependent behavior.
AH.10.01 p.2 documents core-image handling for RUNCOM as well. It says the command maintains a list of public commands that indicates whether each command assumes a current core image, allowing RUNCOM to intersperse SAVE and RESUME. The stated rule is conditional: a core image is kept across two consecutive commands only when the first is supposed to leave one and the second is supposed to expect one. Chaining therefore does not imply that every command inherits a prior command’s image.
These paths make RUNCOM more specific than “a text file that happens to contain commands.” The sequence was integrated with CTSS’s command-dispatch path, while SCHAIN exposed the macro-file form to programs and CHNCOM offered lower-level list control. A modern emulator or document reader should preserve the distinction between a user invoking RUNCOM, a program invoking SCHAIN, and a program constructing a bounded CHNCOM list.
The manual gives enough detail to build a small compatibility test without guessing at undocumented behavior. Prepare a line-marked macro with one CHAIN declaration, two or three commands, a blank line, and both comment forms. Check that six-character arguments survive unchanged, a seven-character argument loses its leftmost character, * text is not displayed, and $ text appears in sequence. Test the end of the macro separately from a hand-built CHNCOM list, whose documented limit is five commands. Keep this test scoped to the dated manual: it validates the text contract, not every CTSS release or undocumented implementation detail.
What the documents establish, and what they do not
The primary record supports a precise claim: CTSS documented reusable command chains with a CHAIN placeholder list, invocation-time arguments, specific line and comment rules, and both command-level and program-level entry points. The 1965 technical notes provide the surrounding 7094 and supervisor context; the guide supplies the actual macro-command behavior.
It is tempting to treat any early command file as a direct ancestor of a later shell or an rc configuration file. The cited CTSS documents establish a functional resemblance (commands are stored in a file and run in sequence), but do not establish a direct transmission of design into Unix or POSIX. That is an evidence limit, not a claim that no influence existed. A careful history can compare the user-facing problem while leaving lineage open unless correspondence, source, or another primary record demonstrates it.
The technical lesson survives the era: “run these commands” is a contract with file-format, tokenization, substitution, and return-path rules. CTSS’s manual made several of those rules explicit, including a six-character truncation that would be easy to miss if one read only the tool’s name. Studying the details shows an early system solving repetitive interactive work in its own supervisor architecture without projecting a modern shell backward onto it.
Related:
- IBM VM/370: Turning One Mainframe into Many Virtual Machines
- POSIX: The Standardization Campaign Behind Portable UNIX Interfaces
Sources: