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