The Unix V6 shell and how control flow worked in it
On Unix, 'test
' and '[
' are two names for (almost) the same program and shell
builtin. Although today people mostly use it under its '[' name,
when it was introduced in V7 along side the Bourne shell, it only
was called 'test
'; the '[' name was only
nascent until years later. I don't know for sure why it was called
'test
', but there are interesting hints about its potential genesis
in the shell used in V6 Research Unix, the predecessor to V7, and the
control flow constructs that shell used.
(This shell is sometimes called the Mashey shell, but the version you can find described in Wikipedia as the 'PWB shell' is rather more elaborate than the V6 sh manual page describes or the V6 sh.c seems to implement.)
The V6 shell didn't have control flow constructs as such; instead it outsourced them to external commands, such as goto(1), exit(1) and if(1). The goto and exit commands worked by changing the seek offset in the shell script, which worked because the V6 shell didn't use buffered input; it read its input line by line (or actually character by character). When they changed the seek offset for a shell script, they caused the V6 shell to read the next line from the new offset, creating either a goto (if the new position wasn't at the end of the file) or an exit (if it was).
The V6 'if
' command is even more interesting for us, because it
actually isn't a control flow construct as such (although you could
use it for control flow in combination with 'goto
'). What it does
is conditionally execute another command. To quote the manual page's
usage section a bit:
if expr command [ arg ... ]
The 'expr' isn't a single argument, it's an expression, as we can
see in usr/bin/chk, and
the syntax of the expression is quite similar to what the V7 'test
'
accepts. It's easy to see how this could be translated into the V7
Bourne shell almost equivalent of 'test expr && command [ arg
...]
', and if you're translating existing scripts that way, a command
with a regular name like 'test
' makes sense. If the V7 'test
'
accepted all of the V6 'if
' expressions, you could mostly do it
with some straightforward 'ed
' commands.
Although I've talked about V6, it turns out that an 'if
' command
in Research Unix goes back very far. Unix V2 has an if.c that does
more or less the same thing as the V6 'if
', although I haven't
checked the expressions it accepts. The 'if
' manual page in V6
cross references 'find
' (presumably for a similar way of constructing
expressions), but it looks like 'find
' appeared later; the earliest
I can find is the V5 find.c. So
the basic idea of 'run a command if an expression is true' is a
very old Unix idea. The V7 Bourne shell 'test expr && command' is
merely the culminating form.
(I'm sure Research Unix didn't invent the general idea of executing
a command only conditionally. I haven't dug deeply into things like
Multics, one obvious source of ideas that Research Unix was drawing
on, but I did spot its 'exec_com'.
I don't know if earlier operating systems used a standalone 'if
'
command equivalent or included it as part of a more complicated
execution control system.)
|
|