A snapshot of the shell being built at Bell Labs.
Isaac (.ike) Levy
ike at blackskyresearch.net
Tue May 12 21:13:39 EDT 2026
Hi All,
It's rare for any presenter, in any technical talk, to even have their slides done the day before their presentation.
However, ahead of the NYC*BUG meeting tomorrow night, Steve Bourne forwarded something he prepared for us in 1978.
Attached, /usr/news updates June 1976 through July 1978. A snapshot of the shell being built at Bell Labs. It shows the actual design decisions as they were happening (spoiler alert):
- $pid -> $$, $r -> $?, $n -> $#, $pcs -> $! (variable names compressing from words to symbols)
- read introduced as a builtin (replacing set -r name)
- export introduced, variables not transmitted to environment by default (this shocked me!)
- PATH replacing the old lowercase $p
- IFS word splitting on read
- The line: "Those who read certain children's magazines will readily recognize these."
Also a reminder, worth a look before tomorrow's fireside chat, where we can discuss more with SRB:
BSTJ 57: 6. July-August 1978: UNIX Time-Sharing System: The UNIX Shell. (Bourne, S.R.)
https://archive.org/details/bstj57-6-1971
Best,
.ike
-------------- next part --------------
Sat Jul 22 22:22:20 EDT 1978
a) As advertised some time ago (see news below)
the shell variables $pid $r $n $pcs
have been replaced by $$ $? $# $!
Also the old path variable has gone.
$PATH is the name of the new path variable.
b) The builtin command `read' has been
modified to allow eg
read a b c d
which will read the next line from the standard
input and place the first `word' in `a',
the next in `b' and so on. A word is delimited
by any character in the shell variable IFS .
c) The -u flag has been added that checks for unset
variables. When set the use of an unset variable
causes a message to be printed and execution
is abandoned.
Thu May 18 01:53:15 EDT 1978
a) By default the shell only interprets keywords
before a command name, as in,
n=v ... cmd args
By saying `set -k' keywords will be interpreted
anywhere in the argument list.
b) The shell now waits for all processes in a pipeline.
This is so that
cat | foo
where foo is not found doesn't leave cat reading
from the terminal.
c) The variables `pid' `pcs' `r' `n' and the old path
`p' have all gone. Most shell procedures in user's
private bins have been converted but a check
should be made anyway.
Fri May 12 01:44:05 EDT 1978
a) The shell has been modified to take advantage
of the new UNIX environment passing stuff
(notably execve). As a consequence shell
variables are initialized from the environment
but are not transmitted back to the environment
by default. Saying
export name
will cause name to be sent to the environment
when processes are created.
The `local' command is a no op for the time being
but will go away sometime in the future.
b) Shell variable names have been changed to upper
case to avoid confusion with user's variables.
The command `fixprof' may be used to change .profile
The following names are known about by sh.
PATH search path
HOME home directory
MAIL mail file name
PS1 the shell prompt ($ )
PS2 the secondary prompt (> )
For the time being if $PATH is not set $p will
be used.
In addition the following have been introduced
to reduce the number of names the shell knows about.
$$ the shell's process number ($pid)
$# the number of arguments to a shell procedure ($n)
$? the return code from commands ($r)
$- the shell flags (-xv ...)
$! the last background command's process number ($pcs)
(Those who read certain children's magazines will
readily recognize these.)
The use of $f to set execution traces has been abolished
sh -x has been reinstated. The current value of such
flags is now avaiable as $- .
For the time being $pid $pcs $n and $r will continue
to be set to allow shell procedures to be converted.
c) It is now possible to have arguments containing =
only interpreted if they appear before the
command name.
The shell flag -l (el) causes the form of
a simple command to be
n=v n=v ... cmdname args
This is upwards compatible with old unix
provided that the command name itself does
not contain the character = .
If this flag is used it means that shell
scripts using the
set command will need modification. In
particular
set name=value
would set $1 to `name=value'. This effect
could not be obtained before since the shell
always treated such arguments specially.
To set variables in the shell just write
name=value
d) The command
set -r name
is now written
read name
`read' is a new built-in command that reads one
line from the standard input and assigns it to
a variable. The return code is 0 unless an end
of file is read.
Fri Apr 14 21:28:48 EST 1978
a) The global command has gone.
Names are by default global and may
be made local using the local command.
(Previously names could not be made
local once declared global.)
b) The `mail' variable is now called `m'.
All variable names affecting shell behaviour
are a single lower case character.
c) The variable used to store the number
of the last background process is now `c'.
It used to be `pcs'.
d) Instead of
set -x
and set -v
a shell variable `f' is read for these
options. (This allows these trace flags to
be saved and restored and if necessary
transmitted to shell procedures.)
set -x now becomes set f=x &c.
e) The shell variables `n' `r' `c' and `pid'
are local.
f) Arguments of the form
name=...
are now treated in a similar way to io
redirection (>file ...). If such an argument
appears (unquoted) then it is absorbed by
the shell and used to update an `associative
memory' attached to each process. This
memory is available to C programs and contains
such things as the terminal name ($t),
the search path ($p) and the home directory
($h).
Previously arguments of this form were treated
specially for shell procedures but not
for C programs.
One consequence of this change is that the search
path is now available from within the editor.
(!mycmd will now work).
g) Variables may be assigned to by saying
name=...
without using the command `set' explicitly.
h) Saying eg
set x=`date`
where the output of date contains
blanks will now assign all of the output to x.
(This is the same as >`date` .)
i) A bug in the handling of substitutions such as
${...${...}} has been fixed.
j) echo */*/* is now interruptable.
k) io redirection of the form ...>&- will close
the associated file descriptor.
l) The path separator character will soon be :
At present both : and - are accepted.
m) "$*" is the same as "$1 $2 $3 ..."
"$@" is the same as "$1" "$2" ...
Previously only $* was available.
n) `chdir' has gone.
Wed Oct 12 22:29:43 EDT 1977
A new command has been added and the previous
distinction between transmitted and non
transmitted variables using _ has
been removed. The new command is called
`global' and has the form
global name ...
and causes the shell variables name ...
to be transmitted to shell procedures.
Mon Oct 10 12:41:21 EDT 1977
There is a new version of the shell.
a) case alternatives may now be written
using the notation
case ... in
...|...|...) etc.
ie the alternative patterns are separated
by |
b) Syntax error messages now include line numbers
and provide a bit more information.
c) The opt command is about to disappear. The set
command may be used instead. eg
set -x
for the execution trace.
d) continue has been added for resuming loops at
the next iteration.
e) The break built-in command may be followed by
an integer giving the numbers of levels of
loop to exit from.
f) A bug in the storage allocation has been fixed.
g) The notation ${...} is now checked more
thoroughly. Also the default strings are only
evaluated when needed so that eg
echo ${d-`newfile`}
will only execute the command newfile if $d
is not set.
h) A new shell option -P has been added.
sh -P profile
will execute the file profile before executing
commands from the usual places.
i) Reaction to DEL should be better, particularly
immediately after typing a command name but
before the command has been executed.
j) trap 0 is now called on all normal exits from the
shell. (eg exit.)
Mon Jul 4 00:33:38 EDT 1977
The notation
args ... ( ... ) args ...
has been removed. (This is an attempt
to remove some little used features
from the shell.)
sh
Mon May 2 23:48:27 EDT 1977
a) digits are now allowed after an initial
letter in shell variable names.
b) saying `readonly r' no longer causes
the shell to loop printing an error
message.
c) An obscure bug relating to interrupt
handling has been fixed. The observed
effect was, in some circumstances, for
the shell to loop after it had received
the signal.
Fri Apr 8 04:07:28 EST 1977
a) The shell prompt can now be set by
opt -p ...
for example
opt -p yes\ dear
b) A bug that occurred when the first argument
in a for list was quoted has been fixed.
c) The text inside `...` was evaluated twice;
it is now evaluated once as a command and
the resulting text is evaluated once.
sh
Wed Mar 9 22:11:18 EST 1977
Command substitution now occurs in in line
documents at the same time as parameter
substitution. Quoted documents are unchanged.
eg
cat <<:
`pwd`
:
will print the output of pwd. It is now
necessary to precede ` in an in line
document with a \ if the special meaning
is not wanted.
Fri Mar 4 17:02:57 EST 1977
Some modifications have been made to the shell. One result
is that it now runs up to twice as fast as the current
shell. It also uses less space. As usual some bugs have
gone and some more have appeared (although in both cases
they escape my test programs).
a) for, while, until, if, case may be preceded and/or fol-
lowed by io redirection. As before piping into or out
of these constructs works as expected.
b) The command-list between the pattern of a case and its
;; may be empty; eg
case a in
a)...;;
*);;
esac
Also the last case may be followed by ;;. The : used
to separate the pattern from its actions has now been
replaced by ). This means that the shell no longer
treats : as a meta character although the command : is
still ignored.
c) The -n flag has been added and causes a shell file to
be checked for syntax but not run.
d) The -i flag has been removed.
e) The for and while constructions have been split. Pre-
viously one could say
for ... while ... do ... done
and various parts could be omitted. There are now two
separate constructions.
for ... do ... done
and while ... do ... done
f) Local names have been added. Variable names beginning
with an underscore are not transmitted by default to a
sub shell. They must be passed explicitly.
g) for and case may now be written
for i in ...
{ ...
}
and case arg {
...
}
h) ps now produces sensible output for running shell files.
i) A new form of default for variables has been added that
sets the variable if it is not yet set. It is written
${name=value} and is the same as ${name-value} except
that the name is set. For example,
: ${a=abc} ${b=def}
is the same as set a=${a-abc} b=${b-def}
and will set a and b to the default values abc and def
j) Argument splitting occurs following command substitu-
tion. To achieve the previous effect write
"`...`"
For example,
for i in `cat x`
{
...
}
will execute ... for each "word" in the file x.
k) Since {...} may now be used where once there was
begin...end the `test' command now has the alternative
form
[ ... ]
eg if [ -d file ]
...
l) wait has been modified to take a single argument. It
will return when that process terminates or when there
are no more processes. `wait' is still interruptable.
m) A new builtin command called `readonly' has been added.
It takes a list of variable names and freezes their
values. Subsequent assignment to such variables is an
error.
n) The shell will exit after 1 hour if no command is typed
at the terminal.
sh
Wed Nov 17 15:28:34 EST 1976
a) A bug that caused input to be buffered when
it should not have been has been fixed.
b) The trap command has been amended to allow
a trap to be set for exit from the shell file.
The command
trap "..." 0
will cause ... to be executed just before exit
from the shell file.
c) The random setting of $r by trap routines
(causing the execution of the trap to destroy
$r) has been removed.
sh
Mon Nov 1 21:13:05 EST 1976
Various obscure bugs have been fixed and some
other minor changes implemented as follows.
a) set a=`cat <<!
...
!`
now works
b) The substituted document is now printed with
the -x option.
c) `for i in $*' may now be written `for i'
the `in $*' is assumed if no in list is given.
d) Some bugs in eval have been fixed eg
eval 'echo a
echo b'
now works.
e) The construction
for i ... done&
and related constructs now work as expected.
f) The : of a case clause may now be written
as ). eg
case $1 in
*.c) ...;;
*) ...
esac
g) A bug in .profile handling that prevented
shell files from working within profiles
has been fixed.
h) Bad options no longer cause strange effects.
sh
Fri Jul 23 07:19:16 EDT 1976
a) When executing shell files error messages are
preceded by the command name ($0).
b) Parameters that are not set can be checked for
in the shell by saying eg
${name?string}
If name is set then its value is substituted,
otherwise `string' is printed and further
execution of the shell file is abandoned.
If string is empty then a standard message is printed.
sh
Thu Jul 15 02:51:41 EDT 1976
a) shift takes an integer argument saying how much to shift by
b) A new command has been added to the shell
to enable shell procedures to be executed
in the shell process (as opposed to
a sub process). The command is called `.'
so tha for example,
. .profile
will execute the file .profile
The standard search path is used when trying
to open the file. Also further arguments may be
supplied in the usual way. For example
. set x y z
where the file `set' contains
echo $*
will echo x y z
and leave $1 $2 $3 set to these values.
c) The exec command now accepts io redirection arguments.
Note that they affect this shell process so that
exec 2>xxx will cause subsequent output to 2 to
be put in the file xxx.
sh
Tue Jun 22 00:55:30 EDT 1976
a) The delimiter for the case command is now
;; and comma (,) has been removed.
b) A bug in the treatment of the path ($p)
has been fixed.
c) '' now gives a null argument.
d) Prompting for input when using << now
occurs if interactive.
e) A bug in the `break' command has been fixed.
f) A bug in the use of `trap' from an interactive
shell has been fixed.
Thu Jun 3 18:21:29 EDT 1976
In response to popular demand a number of changes have
been made to the shell. Please let me know if there
are any problems (srb).
The commands in /usr/sh have been moved into /usr/bin
although this should not be noticeable unless an explicit
request is made for /usr/sh/...
a) $ is no longer used as the quoting character; instead
a \ is used. For example
echo \; will print ;
echo \$ will print $
Within double quotes the meaning of \ is somewhat
modified and the only characters escaped are " $
and newline.
b) A new quoting mechanism '...' has been added that inhibits
all interpretation of the enclosed string. For example
echo '$1' will print $1
echo '\\' will print \\
c) Command substitution is now written
` command `
Nested uses now need to be quoted.
d) Input substitution is no longer provided so that % is
not a shell meta character. A similar effect can be
achieved using `eval' (qv).
e) The delimiter for case commands is ;; although , will
remain for a short time until shell files have been changed
over.
f) `here' documents are processed in one of two ways
depending on whether the string following << is quoted or
not.
fa) not quoted (eg <<!)
A \ is used to escape a newline, a $
and the first character of the terminating
string. Parameter substitution occurs
within the document.
fb) quoted (eg <<\!)
All characters are passed literally.
No parameter substitution occurs.
g) If a command name contains a / then the prepending
More information about the talk
mailing list