2023-12-03
A bit more trivia on the Unix V6 shell and its control flow
Over on the Fediverse, I posted about how the V6 'goto
' and
'exit
' worked, and got a good question in
response, namely
how did 'goto
' and 'exit
' get hold of the file descriptor for
the script that the V6 shell was executing. The answer turns out
to be that the V6 shell always read from standard input (fd 0). If it was
running a script, it arranged to open the script with file descriptor
0 (standard input), which it passed on to all children as usual.
(In my Fediverse answer I said it used 'dup()
', but the V6 sh.c
says I'm wrong. V6 sh.c simply closed fd 0 just before it open()'d
the script, insuring that the open() would give it fd 0. There was
also special code to 'read' from the -c command line option instead
of standard input.)
Obviously this has certain limitations, like you'd better not write shell scripts using programs that read their standard input as a side effect of other operations (at least not without a '</dev/null' or the like). But as Gaelan Steele noted, it's a very early Unix way to handle the whole thing.
Also, Norman Wilson noted that this is where we get the ':' command to do nothing, which would later be one of the ways of writing comments in shell scripts. However, V6 isn't where either ':' or 'goto' appear; a version of 'goto' can be found as far back as V2's goto.c, and just as in V6 it searches through standard input for a line with ': ' at the start. I believe that ':' was always built in to the Unix shell, making it one of the oldest builtins along with 'chdir' (what eventually became 'cd'), although it's not mentioned in the V3 sh manpage.
(Unfortunately we don't seem to have the source for the V3 shell,
and neither source nor manual page for the V2 shell. But I can't
imagine early Unix not making ':' a built in command like 'chdir',
and we know you could put ':' in shell scripts due to 'goto
'.)
Update: To explain the connection between 'goto' and ':' a bit more, how 'goto' worked is that your script did 'goto label' and goto searched through the script for a line that said ': label' (for an arbitrary word as the label) and positioned execution there. In order to make this line valid in a shell script, there was a ':' shell builtin that did nothing.