AOS/VS (32bit CLI)
CLI32, the 32-bit rewrite of Data General's Command Line Interpreter for AOS/VS: a bracket-and-percent-sign macro language descended from the 1976 AOS CLI that ran the batch jobs and logon macros of Eclipse MV minicomputers.
Created by Data General Corporation
AOS/VS (32bit CLI) is CLI32, the 32-bit Command Line Interpreter for Data General’s AOS/VS and AOS/VS II operating systems. These ran on the Eclipse MV family of 32-bit minicomputers. CLI32 was a rewrite of the 16-bit CLI that Data General had shipped with AOS since 1976, and it kept that CLI’s odd and fairly capable macro language. Scripts are plain .CLI text files. Arguments are written as %1%. Anything in square brackets is expanded before the command runs, whether it names a file, a macro or a built-in “pseudo-macro” such as [!DATE]. Conditionals are written [!EQUAL,a,b] … [!ELSE] … [!END]. On an Eclipse MV system, logon macros, batch jobs, system-management scripts and some of Data General’s own utilities were all written in this language.
History & Origins
The AOS CLI (1976)
Data General already had a “Command Line Interpreter” for its RDOS operating system on the Nova and Eclipse by early 1975. When the company released the Advanced Operating System (AOS) for its 16-bit Eclipse minicomputers, the CLI came with it. The Command Line Interpreter (CLI) User’s Manual (document 093-000122) gives its original release as April 1976. The same document was revised in 1977, 1978, 1979, November 1980, May 1982, February 1984 and October 1984. That makes it an unusually complete record of how the language changed.
AOS/VS and the 32-bit Eclipse MV (1980)
In 1980 Data General introduced the Eclipse MV/8000, its first 32-bit minicomputer. It was code-named Eagle and is the machine whose development Tracy Kidder described in The Soul of a New Machine. The new operating system was AOS/VS (Advanced Operating System/Virtual Storage). It used the MV’s eight protection rings and ran 16-bit AOS programs unchanged. The CLI came across as well. The October 1984 manual covers both “AOS Rev. 6.00” and “AOS/VS Rev. 5.00” and says:
The CLI utilities for AOS and AOS/VS are almost identical. In the few instances where a CLI command or command switch is valid for one operating system but not the other, we highlight the difference.
At this stage the CLI running on 32-bit AOS/VS was still a 16-bit program. A batch listing from Atari in January 1984 identifies it as AOS/VS CLI REV 03.03.00.00.
CLI32 and AOS/VS II
AOS/VS II came out in 1988. It started as AOS/VS revision 8.00, but it introduced a file system that was incompatible with the old one, so Data General gave it its own revision numbers starting at 1.00. The original system carried on as maintained “classic” AOS/VS. Secondary accounts, including Wikipedia’s AOS article and an Easter-egg write-up on eeggs.com, say AOS/VS II brought a new interpreter, CLI32.PR, which was a complete 32-bit rewrite of the old CLI. The original CLI was then usually called CLI16. No dated Data General announcement of CLI32 has turned up, so its exact release date is uncertain. By August 1992 it was clearly shipping on both systems. The AOS/VS Revision 7.70 Release Notice lists about 150 numbered CLI32 fixes, refers to “the initial release of CLI32”, and warns about behaviour that differs “from CLI16 and CLI32 from earlier revisions”.
The two interpreters were installed side by side. The [!CLI] pseudo-macro returns CLI16 or CLI32, so a macro can check which one it is running under. The 1993 Phrack guide does this in its example code, and prints a message if the reader is “using CLI16 which won’t let READ take arguments.”
Design Philosophy
The CLI works by textual expansion. It does not parse the input into an abstract syntax tree. Before a command runs, the CLI rewrites the line. Dummy arguments are replaced with actual arguments, bracketed file names with the contents of those files, and bracketed pseudo-macros with their values. Only then does it run what is left. The idea is similar to what Unix shells do with $1 and `command` substitution, but the CLI takes it further:
- Macros are only files. Typing
TOPmakes the CLI look for a command calledTOP, then forTOP.CLIin the working directory and search list. Writing[TOP]explicitly substitutes the file’s contents, so a macro can have the same name as a built-in command. - Conditionals are expansions too.
[!EQUAL,x,y]can appear inside an argument to another pseudo-macro. The manual shows a single statement that tests whether three arguments are all equal by nesting[!EQUAL]…YES[!ELSE]NO[!END]inside the arguments of an outer[!EQUAL]. - Switches are part of the language. DG command syntax uses
/SWITCHand/SWITCH=valueeverywhere, and the macro language can pick switches apart.%1/S%includes the first argument’s/Sswitch,%2\L%includes every switch except/L, and%0/T=%gives the value of a/T=switch on the macro’s own name. - The environment is stacked.
PUSHopens a new CLI level with its own search list, working directory, list file, string, prompt and error-handling settings, andPOPrestores the previous level. Well-behaved macros push on entry and pop on exit.
Key Features
Dummy arguments
| Form | Expands to |
|---|---|
%0% | The macro name, with all its switches |
%n% | The nth argument, with its switches |
%m-n,i% | Every ith argument from m to n (defaults: m=1, n=32767, i=1) |
%-% | Every argument |
%n/% | Only the nth argument’s switches |
%n\% | The nth argument without its switches |
%n/S=% | The value of the nth argument’s /S= switch |
This example from the 1984 manual swaps the names of two files:
| |
Parentheses make a command repeat. If ASM.CLI contains XEQ MASM/L=%1%.LS %1%, then calling ASM (FILEA,FILEB,FILEC) runs the assembly three times, once for each file.
Conditional pseudo-macros
[!EQUAL] and [!NEQUAL] compare any two strings without regard to case. [!UEQ], [!UNE], [!ULT], [!ULE], [!UGT] and [!UGE] compare unsigned decimal integers. Each block ends with [!END], with an optional [!ELSE] before it:
| |
If a macro is missing an [!END], the CLI prompts with !) when it is inside a true branch and \) when it is inside a false one. It waits until you type the missing [!END].
Arithmetic and system pseudo-macros
[!UADD], [!USUB], [!UMULTIPLY], [!UDIVIDE] and [!UMODULO] work on unsigned integers up to 4,294,967,295. Results wrap modulo 4,294,967,296. [!OCTAL] and [!DECIMAL] convert between number bases. Other pseudo-macros query the system, including [!DATE], [!PID], [!USERNAME], [!SEARCHLIST], [!FILENAMES template], [!SIZE file] and [!CONSOLE]. [!READ prompt] writes a prompt and expands to whatever the user types in reply. CLI32 adds /LENGTH=, /EOF= and /FILEID= switches to [!READ] so that it can also read from files.
Loops: recursion first, then real loops
For most of its history the CLI language had no loop construct. The 1984 manual shows how to get one: a macro that calls itself.
| |
DO_INCREMENT TEST 2 10 3 runs TEST with the index at 2, 5 and 8. AOS/VS Revision 7.70 (August 1992) finally gave CLI32 [!LOOPSTART] and [!LOOPEND], along with [!EXIT/LOOP], [!EXIT/MACRO] and [!EXIT/ALL].
Example: 99 Bottles of Beer in CLI32
Robert de Mander of Robdem Soft AB wrote this CLI32 version, published on his Robdem Soft pages (it was reportedly also submitted to 99-bottles-of-beer.net). It uses a VAR0 variable, the 7.70 loop pseudo-macros, \\ lexical comments and a trick with the parity bit. In the author’s words, [!ascii 254] is “really a comma with the parity bit set, and write/7bit strips it away”. The trick is needed because a literal comma would act as an argument separator.
| |
The pluralisation logic is bottle[!une,[!var0],1]s[!end]. It is a conditional placed in the middle of a word, and it shows how this language treats control flow as text substitution.
Error handling
Errors fall into two classes, CLASS1 and CLASS2. Each class can be set to ABORT, ERROR, WARNING or IGNORE for the current environment level, and any single command can override that with /1= or /2=. For example, CREATE/2=IGNORE file keeps going if the file already exists. CLI32 lets every command take the global switches /STR= and /ESTR=. The 7.70 release notice explains that /ESTR=name writes a command’s error message into a named string, which a macro can then test instead of simply stopping.
Evolution
| Period | Interpreter | Notable language changes |
|---|---|---|
| 1976 | AOS CLI | Manual 093-000122 first released (April 1976) |
| 1980-1984 | 16-bit CLI on AOS and AOS/VS | By Rev. 07 (Oct 1984): dummy-argument ranges and switch extraction, nested conditionals, unsigned 32-bit arithmetic, PUSH/POP environment levels, ; for several commands on one line, & for continuation lines |
| c. 1988 (by 1992-1993 at the latest) | CLI32 with AOS/VS II | 32-bit rewrite; CLI32-only PRIVILEGE and PASSWORD commands, group ACLs, extended [!READ], global /STR= and /ESTR= switches |
| Aug 1992 | CLI32 in AOS/VS 7.70 | [!LOOPSTART]/[!LOOPEND], [!EXIT], %[!VAR0]% inside dummy arguments, /7BIT, [!SYSTEM/SPECIFIC], rule for reading two-digit years |
| 1990s-2001 | CLI32 3.2x on AOS/VS II | Maintenance and year-2000 updates; Release 03.21.00.00 seen in 2001 |
CLI16 was not removed. The 7.70 release notice still lists CLI16 enhancements, such as ?PRIVILEGE support “with prompts SuSpSm compatible with CLI32”. Sites could run either interpreter, and a 2001 session log shows both on the same machine.
Current Relevance
AOS/VS and AOS/VS II are discontinued. Eclipse MV hardware was obsolescent by the late 1990s, and EMC bought Data General in 1999. Sarpy County replaced its MV30000 in 1996 rather than rewrite 2,500 AOS/VS COBOL programs, which illustrates the choice facing the remaining installations. No Docker image exists, and there is no public, redistributable way to run CLI32 on modern hardware. What survives is mainly documentation: Data General manuals and release notices kept in online archives, the 1993 Phrack guide, and pages written by long-time administrators recording tricks and Easter eggs from these systems.
Why It Matters
The AOS/VS CLI was a well-developed command language on a commercial minicomputer at a time when many systems had much more limited job-control languages. Inline expansion of [!pseudo-macros], pattern-based argument ranges, macros that can read their own switches and stacked environment levels made it a real scripting language for the shops that used Eclipse and Eclipse MV systems. It also shows the downside of building everything on text expansion. Loops had to be written as recursion for more than a decade, commas and brackets needed tricks such as the parity bit to print literally, and the 7.70 release notice records how fragile & continuation at end-of-file could be. For anyone studying shell design, CLI32 is a well-documented example of a command language that developed separately from the Unix shell tradition.
Timeline
Notable Uses & Legacy
Atari software development system
A January 1984 batch-output listing from Atari's 'S/W Development HCD1' system, reproduced on Wikipedia, shows the AOS/VS CLI (rev 03.03) running a queued .CLI job. The job sets the search list, directory and default ACL, then runs Atari's CAMAC assembler
Data General system utilities
Data General shipped some utilities and languages as CLI macros rather than programs. The 1984 manual notes that for these you 'do not begin the command line with XEQ', and under CLI32 the LOAD command is a macro that calls the DUMP_II program
Sarpy County, Nebraska
Until 1996 the county's core system was a Data General MV30000 running AOS/VS, with about 500 users (175 to 200 each day) and 2,500 AOS/VS COBOL programs, according to a July 1997 FOCUS user-group case study. On sites like this the CLI was the operating environment for logons, batch queues and job control
Logon macros and batch jobs on Eclipse MV sites
Interactive sessions and batch jobs on AOS/VS normally ran under a CLI process (the 1984 Atari listing shows one starting and terminating around a batch job). The initial logon macro and queued .CLI job files were written in the CLI language, and the Revision 7.70 notice adds a CLI32 /NOCA switch so that console interrupts are ignored while the logon macro runs