ARG_MAX
| Shells
| whatshell
| portability
| permissions
| UUOC
| ancient
| -
| ../Various
| HOME
$@"
| echo/printf
| set -e
| test
| tty defs
| tty chars
| $() vs )
| IFS
| using siginfo
| nanosleep
| line charset
| locale
2001-10-07 .. 2019-09-16 (see recent changes)
This page is about all the variants of the original Bourne shell - it doesn't deal with bourne compatible shells like the korn (ksh), almquist (ash), bourne again (bash) or posix shell.
The Bourne shell, introduced with the "7th edition" of Unix in 1979, is an important part of the Unix history. Its grammar is the core of several modern shells. Even some later variants of the traditional Bourne shell are in use until today. However, there's little common knowledge about these traditional Bourne shell variants, because they never had been "versioned". This page tries to document their way.
Originally, this page started with a rough english translation of <3B9529F8.2RV1IN16U@bigfoot.de> from de.comp.os.unix.shell. Credits for that posting and for countless further comments to Gunnar Ritter. Without The Unix Heritage Society (TUHS) the early releases couldn't have been documented in detail here. Many thanks also to Dennis Ritchie for access to the Version 8 shell and to Warren Toomey (TUHS) concerning the SVR1 shell. I inspected the Bourne shell on these unix systems (credits included). If you can provide further information, I really would like to hear from you.
Find more information about the origins of the Bourne shell at the bottom of this page.
How to identify a traditional Bourne shell?
1  
A simple check for an often undocumented but characteristic feature:
You can use the circumflex ^ (caret) as replacement for | (pipe).
This was inherited from the predecessor, the Thompson shell, probably
for reasons of convenience
on early upper-case-only terminals.
See more common characteristics that are
unique to traditional Bourne shells. 2
And how to identify the very version? As no version info has been compiled in 3, you have to test for specific features. Running the script whatshell helps to unravel the version. The script is a consequence of this page.
 Thanks to the OpenSolaris project, Gunnar Ritter could publish
a source port of
a SVR4 variant of the Bourne shell.  This was the first officially
available later Bourne shell on free unix flavours.
 Jörg Schilling has also published a
port
of the OpenSolaris variant and he has added numerous extensions.
Some issues are covered in more detail on subpages and linked inline below; here is a list of all these subpages.
Unsolved: Bourne shell before3 the well known 7th edition (~3 years of unreleased development). Better differentiate among SVR3.x and SVR4.2x.
| [1] |  
    Naturally, virtually all commercial systems provide
    a traditional Bourne shell.  Meanwhile, you'll find it at a different path
    on some systems (e.g., HP-UX 10 ff., /usr/old/bin/sh)
    or under the different name bsh (e.g., on AIX 4 ff. and
    IRIX 6.4 ff.).  On Ultrix you'll find a second variant as
    /bin/sh5.  On OSF/1 there is the optional
    /usr/opt/svr4/usr/bin/sh.
    See also  various system shells.
     No rule without exception: HP stopped including it with release
    "HP-UX 11i Version 1.5" (and Cray had stopped including it with
    "Unicos 9").
 | 
| [2] | If you're interested in general script portability, then have a look at Paul Jarc's list of suspicious or nonportable constructs concerning modern portable script-writing. | 
| [3] |  
   The Version 7 variant contains a char* version = "\nVERSION sys137  DATE 1978 Nov 6 14:29:22\n".
   However, it's not used, remains unchanged in the source in following releases and disappears with SVR2 (when the source is de-algol68ized).  | 
A summary of the most important changes
| · Version 7 | (1979) | control structures,  cmd substitution,  () and {},  arbitrary variable names,  trap,  eval,  special parameter substitutions, case
 | ||
| · System III | (1981) | #,  [!...],  colon parameter substitution,  set --
 | ||
| · SVR1 | (1983) | shift n
 | ||
| · SVR2 | (1984) | functions,  built-ins: unset echo type,  redirection for builtins
 | ||
| · SVR3 | (1986) | modern ",
	  8-bit clean,
	  getopts,
	  functions do not modify positional parameters
 | ||
| · SVR4.0 | (1989) | job control | ||
| · SVR4.2 | (1992) | read -r
 | 
Table of contents
     · Version 7  (and 2.9BSD)
	and 3BSD and 4.xBSD (and Sinix 5.20 (ucb universe), SunOS 2)
	- Ultrix
	- Dynix 3.2 (ucb)
	- DomainOS 10.3
     · System III  (and Plexus 1.0)
	and SINIX 5.20 (sie)
     · SVR1
	and Iris 3.7
     · SVR2  (and MV/UX 3)
	and Ultrix sh5
	- Version 8
	- SunOS 3
	- OSF/1
	- HP/UX
	- Dynix 3.2 (att) 
     · SVR3  (and MUNIX V3, SINIX 5.20 (att), SCO Xenix 2.3.4)
	and SunOS 4
	- AIX
	- IRIX 3/4
	- SCO Unix
	- Interactive Unix
	- DG/UX 40
	- DomainOS 10.3
	- Dynix PTX
     · SVR4  (and OSF/1-SysV)
	and SunOS 5
	    - Heirloom
	    - Schily
	- IRIX 5/6
	- DG/UX 42
	- EP/IX
	- Reliant UNIX
     · SVR4.2  (UnixWare, OpenUnix)
And now all the very details:
The item "Version 7" lists some important
differences to its predecessors and successors.
All subsequent items list the differences to their
predecessor as complete as possible.
if/switch/while, but called an
     external goto to move the filepointer.  As of mid'76, they were all built in.
>& <& and <&- >&-
     (especially proper handling of stderr)
`...` (command substitution)
() and {}
IFS
trap
     (proper signal handling, onintr in the PWB shell
      just called goto)
case
${-=?+}
eval
umask.
     PS2 functionality
envx
A quick glance at differences to later variants:
unset" facility, i.e., no way to remove
     variables from the environment (instead of assigning the empty value)
[" built-in available (even not as external command
     on Version 7), but only the external "test"
#', is not a comment character yet
     5
/etc/profile (i.e., no global profile)
set -- to separate options from arguments
chdir" is an undocumented alias for "cd" (compatibility to Thompson shell)
break n" exits script if n is higher than the actual nesting level
continue n" doesn't work, it behaves like continue 1 (missing code)
| [4] |  
	The PWB aka Mashey shell also evolved from the Thompson shell.  The main motivation
	 for its creation was providing for large amounts of procedural automation.  | 
| [5] |  
    Without '#', comments are only available by the null-command,
    ':' (colon),but naturally not without possible side effects. A very special example is " : `echo output 1>&2`".
    Enclosing the comment in single quotes protects against side effects.  | 
| [6] |  
    A Bourne shell not being 8-bit clean shows subtle bugs, e.g., when using the
    special forms of parameter substitution in connection with double quotes:
     The internal quoting mechanism sets the 8th bit for quoted characters and accidentally this is not removed afterwards. - One example: ${var?abcde} expands to "var: abcde",
    while ${var?"abcde"} incorrectly expands to "var: áâãäå".
    - Another example: after expanding ${var="$value"} with $value containing spaces,
    $var won't contain real spaces, but non-breakable spaces.
    This might become relevant with subsequent word splitting. Side note: bash before release 1.13 also made use of the 8th bit for internal quoting.  | 
/bin/csh if
	 the first character of an executable script is '#'
	 TIMEOUT (hardcoded in the source) activated by changing from 0 to 2400 (seconds, that is, 40 minutes)
	#' introduced.
	uid=0 or if euid!=uid
	set -e" is disabled while executing an if/while/until condition
	O_APPEND instead of seek()
	| [7] |  
      In the traditional BSD line, the Bourne shell was shipped
      until 4.3BSD-Reno (but not anymore with Net/2 and the following 4.4BSDs).
       For license reasons it was then substituted with the bourne-compatible, svr4-like sh by Kenneth Almquist
	(often called ash).
     | 
| [8] |   
     SINIX offers three universes: "ucb",
     "sie"(mens) and "xopen" (aka "att").
      These provide shells from 4.2BSD, SystemIII and SVR3, respectively. Here are some notes about the sinix universes.  | 
/bin/sh, see below for /bin/sh5)
    ulimit [-f]" built-in (backported)
	/etc/profile (global profile, backported, undocumented)
	TIMEOUT (hardcoded in the source) deactivated again by changing back from 2400 to 0
	continue n" works (backport from SVR2?)
	trap statements with syntax errors (avoids "longjmp botch" error) (06-85)
	     
	continue n" works (backport from SVR2?) (11-85)
	     
	IFS (05-86)
	     
	if false; then...") (07-89)
		
	
		
	fork checking improved and new error messages
	     (probably backported from System V, that is, System III) (04-90)
		
	signal() instead of system version, so that system calls are
	     not restarted after interruption (06-90)
		
		
	SVR2 variant) (1992/93)
    /etc/profile (only executed if login shell)
    > and >> redirections set APPEND bit on file descriptor,
	for usage with dynix parallel make
	(see the according section in the release notes)
    set" recognizes "--" as option
       delimiter, for arguments with a leading "-"
       or "+" (backport from Dynix/PTX, i.e., post-SystemIII)
    PARALLEL controls the number of executed background jobs
	(for usage with parallel make)
	(see the according section in the release notes)
    ENOEXEC the magic is inspected,
	and a diagnostic message is printed if the binary has been compiled for
	a different hardware (i386 vs ns32000)
    csh upon # magic) only in ucb universe
    shift" accepts a number (backport from Dynix/PTX, i.e., post-SVR1)
    break n" doesn't exit script if n is higher than the actual nesting level
    continue n" works
    set -e" is disabled while executing an if/while/until condition
    SHENV: path of script
	 executed at invocation of each new shell
    -Dname=value: supply environment variables
	 (for calling from binary executables)
    | [9] | DomainOS offers two universes: "bsd4.3" and "sys5.3" each providing an according shell variant. | 
/etc/profile
	(always executed, not only for login shells; disctinction possible by leading "-" in $0)
  #'
  ${parameter:=word}"
  [...]" , e.g., "[!0-9]"
       (not documented yet)
  set" recognizes "--" as option
       delimiter, for arguments with a leading "-"
       or "+"
  set" knows "+" to unset a
       respective switch
  -" (turn off flags x and v) is not needed
       anymore but (probably accidentally) remains active without being documented
       anymore.
       test", aka "[", added
       (the latter actually was always existent in code, but commented out)
  read" strips the leading IFS characters (undocumented)
  read" recognizes multiple IFS characters as one
       field delimiter when reading several variables (undocumented)
  <<-" strips leading tabs
  if false ;then :;fi;echo $?" formerly
       wrongly yielded the exit status of false
       (essential fix for the "-e" flag)
  continue n" works (you couldn't jump to outer loops before)
  echo */" resulted in a SEGV if there were filenames
       with metacharacters
  fork checking improved, new error messages
       "cannot fork: too many processes" and "...: no swap space".
  -r") added.
       The environment variable SHELL is inspected at start-up.
       -r" was listed under SYNOPSIS 
	and accepted by the shell, but no functionality was implemented
	and it was not mentioned otherwise.
  exit" allows leaving an interactive shell now
  chdir" deactivated (undocumented)
  login" removed
  RES ("research unix"), which deactivates
	restricted functionality, umask, [ alias for test,
	login
read" doesn't strip the leading IFS characters
    read" doesn't recognize multiple IFS characters
	 as one field delimiter when reading several variables
    display" built-in identical to
	 the "echo" utility.
	 (The echo built-in comes in SVR2.)
    chdir" not deactivated
    ulimit" (show file size limit)
  shift" accepts a number
  cd" knows CDPATH
  test" knows -p to check for named pipe
  set -e" is not passed on to forked child scripts
	(because a script called like a command is not execed but forked)
  set -e" has no influence on commands in the same line ("set -e; false")
  read" is called w/o arguments
    ulimit" is called w/o arguments
    return" built-in)
type unset hash echo pwd"
set | pg" or "read variable < file"
"$@" (or ${1+"$@"}),
     empty arguments are not discarded anymore (not to confuse with the
     later, modern "$@")
& or ``)cat<<EOF& ..."
     or "a=`cat<<EOF ...`"
     (was: "/tmp/sh12345: cannot open")
break n" doesn't exit script if n is higher than the actual nesting level
continue n" works
eval 'echo foo>a' >b" (was: "illegal io")
-afh" 
readonly without arguments doesn't list the exported
     variables anymore
MAILCHECK, MAILPATH.  Bug: Mailcheck must not be empty
hash built-in introduces an (academic) internal limit
break 0" in a one-fold loop renders an interactive shell dysfunctional
SHACCT
$FILEMATCH removed, which had never been active.
     If the code were active, the variable would contain the last element
     of a line after word splitting at each time (even while splitting).
/bin/sh )
    type output
	 for case in a function fixed
    signal() instead of system version,
	 so that system calls do not restart after interruption (11-89)
	 
    LOGNAME via getpwuid() (12-89)
	 
    
    SHACCT not activated on Ultrix
    /bin/sh5 )
HISTORY, pointing to a writable
	 file, providing a history mechanism by
	 "=(1)"
    type is replaced by whatis,
	 which produces output that can be re-evaluated by the shell
    builtin", assuring that nothing else is
	 called instead (e.g., a function),
	 also needed for "whatis"
    echo test hash pwd ulimit" and their
	 implications are gone
    * matches all files but . and ..
    -p": removing function-definitions imported
	 from environment, setting IFS back to default value
    {' and '}' are special
	 like '(' and ')',
	 i.e., syntactically equivalent (e.g., leading blank
	 and terminating delimiter aren't necessary anymore,
	 redirection may also appear at the left side)
    [...]" with '^',
	 instead of '!', e.g., "[^0-9]"
    :' and its side effects, or with
	 ";;" in "case" )
    ^' is gone
    /etc/profile
    SHELL and "readonly" are also gone)
    <<-" (strip leading tabs in here-documents)
    cd" provides an automatic spell checker, for absolute paths only:
	 automatically take the next best matching directory (undocumented)
    f()command>x" works (was: "syntax error").
	 Note that the redirection always, even with braces, ends
	 in the body, though. (also in POSIX.2)
    type output
	 for case in a function fixed
    MAILCHECK and MAILPATH are gone
	 (MAIL is kept)
    | [10] |  
     Most modifications for the Version 8 shell were driven by the
     motivation for a clean design.
      Consequently, the fact that function calls overwrite the positional parameters was not changed.  | 
exec() fails, and before trying to interprete the file itself,
	SunOS 3 checks in advance if the first character is
	Cannot exec binary file".
	test" knows -h to check for symbolic links
	test: too many arguments" added
   LC_CTYPE/LC_COLLATE
   	-D for debugging as compile time option)
   BIN_SH the shell
	forks to a POSIX.2 compliant shell ("xpg4") or an optional SVR4-like
	shell ("svr4").
   ulimit" doesn't only know about file
	size, but is implemented with the 4.2BSD/SVR4-like
	getrlimit(2)
   echo" knows "-n"
   [...]"
   cat <<`...`" anymore
	(and the backquotes have no special meaning)
   test" knows -L and -h to check
	for symbolic links, and -e to check for existence
   argv[0]
	is rsh or -rsh
   */" and
	".*/" to directories (apart from */.)
   cd"
	(linked in from libc) instead of only "bad directory",
	and additionally "cd: too many arguments"
   type" returns false on "not found"
   type" doesn't write "...is a function" anymore
	but only the function definition itself
   type" speciality: if both a command and a function exist, "type" reports both
   type output
	for case in a function fixed
   umask: Improper mask" error message added
   TIMEOUT dynamic environment variable mechanism (unit is minutes)
   argv[0] instead of current one)
	if opening a file for execution fails, that is,
	sh notexist" print
	"sh: notexist: cannot open" instead of "notexist: notexist: cannot open"
   hash": error message "bad hash options"
	instead of standard "bad option(s)"
   PATH is unset) is
	":/usr/bin" instead of ":/bin:/usr/bin"
	/bin is a symbolic link to /usr/bin like on most commercial flavours).
	uid 0 has a different built-in path: "/usr/sbin:/usr/bin:/usr/bin:/sbin",
	though /usr/bin appears twice by mistake
   login" reactivated (undocumented), because:
   RES removed
   inlib" and "rmlib" as built-ins (documented as unsupported)
   inlib" and "rmlib" not documented anymore (still active)
    | [11] |  
     The Migration Guide
     "
     System V Environment for Digital UNIX Version 4.0." (560 kB PDF)
     claims, that /bin/sh on OSF/1 V4 and V5 is a SVR3.2 shell.
      However, it's missing some characteristic properties of this shell (modern "$@", " getopts", the PATH fix
     and "read: missing arguments").
     After all, it looks like a SVR2 shell with numerous fixes/backports from later variants. All source files contain a copyright from "International Business Machines Corp. 1989" and several fixes are coded like the SVR3 variant on AIX.  | 
LC_CTYPE/LC_COLLATE
   LINES and COLUMNS based
	on SIGWINCH
   [...]"
   test" knows -h to check for symbolic links
   pwd" knows "-H"
	for socalled context dependent files, cdf(4)
   argv[0]
	is rsh or -rsh.
   | [12] |  
	To try the unicode support on HP-UX with a remote connection, you need
	an according font and the ability to insert multibyte characters.
	 Try Thomas Dickey's XFree86 Xterm with Markus Kuhn's fonts. Set LC_COLLATE and LC_CTYPE after
	looking at "locale -a" and also set "stty -istrip cs8".
     | 
argv[0]
	is rsh or -rsh
   SIGTSTP SIGTTIN SIGTTOU are ignored in interactive mode
	(for correctly "interacting with the ucb universe")
   '/' (todo)
   (/usr/att)/bin/sh )
  cd" fails, system error messages are printed
     (formerly, the shell only knew "bad directory")
getopts"
PATH
     
     did not
     mean "." before (however, it should behave like execvp(2))
[...]"
IFS='\' wrongly doesn't split anymore
     (demonstrate with var='x\y';set $var;echo "x:$1 y:$2")
r' somewhere in
     argv[0], but only for rsh and -rsh.
read" knows the error message
     "missing arguments"
var=x;echo ${var-'$'} results in
	"bad substitution"
     (probably due to the changed internal quoting mechanism).
      '"' and '`' as values,
      for all but the ":+" and "+" form of
      parameter expansion.
/usr/5bin precedes /bin in
	PATH, built-ins behave sysv-like
	("test": string length with -l;
	 "echo": escape sequences,
	 -f checks for regular files instead of non-directories)
   exec() fails, and before trying to interprete the file itself,
	the shell checks in advance, if the first character
	Cannot exec binary file". (like SunOS 3)
   test" knows -h to check for symbolic links (like SunOS 3)
   test: too many arguments" added (like SunOS 3)
   ulimit" built-in 13
   $SHELL). restricted functionality
	even not documented anymore.
   LC_CTYPE/LC_default
   ./(M-d): permission denied"
	(instead of "./ä" - example assumes your browser
	 supports iso-8859-1)
   type
	output for case in a function almost fixed
   chdir" reactivated (undocumented)
   PATH is unset) is ":/usr/ucb:/bin:/usr/bin"
   | [13] |  
     On SunOS 4, the "ulimit" built-in is not implemented at all.
     getrlimit(2) lists this under BUGS
     (but in fact this origins from 4.2BSD).
     File size limits are catched with quotas instead, and apparently Sun didnt't want to add support by getrlimit(2) otherwise.
     | 
LC_CTYPE/LC_COLLATE
   ulimit" is implemented with the 4.2BSD/SVR4-like
	getrlimit(2)
   test" knows -L to check for symbolic links
   cat <<`...`" anymore
	(and the backquotes have no special meaning)
   [...]"
   IFS='\' splits correctly again
   argv[0] instead of current one)
	if opening a file for execution fails, that is,
	sh notexist" print
	"sh: notexist: cannot open" instead of "notexist: notexist: cannot open"
   TIMEOUT dynamic environment variable mechanism (unit is minutes)
   ${var-'$'} and related parameter expansions bugs
	(which were introduced with SVR3)
   type returns false on "not found"
   migrate" for migrating processes to other "sites".
	"setspath" for using different "sites".
	setxvers" for setting an
	"experimental version prefix" (in connection with
	using "hidden directories").
	In contrast to the documentation, "onsite" is not
	implemented.
   read: missing arguments"
   type output
	for case in a function fixed
   PATH is unset) is
	":/usr/bin" instead of ":/bin:/usr/bin"
	/bin is a symbolic link to /usr/bin like on most commercial flavours).
	uid 0 has a different built-in path: "/usr/sbin:/usr/bin:/sbin"
   limit" and "unlimit"
	 as interface to getrlimit(2)
    test" knows -l to check for symbolic links
    
-L" for "cd" and "pwd"
	     added, toggling between using logical or physical pathnames,
	     i.e., wether navigation along symbolic links is remembered
	cd" provides a spell checker (inherited from Xenix)
	test" knows -L and -h to check
	     for symbolic links
	LC_CTYPE/LC_COLLATE
    test" knows -H and -M to check
	     for a semaphore or shared memory, respectively
	cat <<`...`" anymore
	     (and the backquotes have no special meaning instead)
	umask -S" knows the symbolic notation.
	     "Bad umask" error message added.
    LINES and COLUMNS based on SIGWINCH
    SIGSEGV for internal memory management
	     to better recognize real SIGSEGVs.  Instead it's checking and
	     expanding in advance.
    ulimit" implemented with getrlimit(2) (underlying UnixWare 7 SVR4.2 kernel)
	argv[0]
	is rshell or -rshell
    DOSPATH for .exe, .cmd
	 and .bat
    SHENV: path of script
	 executed at invocation of each new shell
    -Dname=value: supply environment variables
	 (for calling from binary executables)
    | [14] | DomainOS offers two universes: "bsd4.3" and "sys5.3" each providing an according shell variant. | 
PARALLEL controls the number of executed background jobs
	(for usage with parallel make)
    bg fg jobs kill stop suspend"
-m" to switch on/off
     job control.
ulimit" now implemented with getrlimit(2)
-p"
     trap" now accepts symbolic signal names
test" knows -h to check for symbolic links.
/usr/ucb/ precedes
     /usr/bin/ in PATH (BSD compatibility):
	echo" knows "-n" and disables backslash escape sequences,
    test -f" doesn't check for a regular file but for "not a directory". 
	: > file") in a for- or while-loop is executed
     only the first time (although the colon command is executed each time)
     
exec > file")
     in a loop works only the first time,
     that is, all subsequent output shows up in the first place
     
$-) when becoming restricted
     by SHELL or argv[0]
env 'A B=1' sh"
        ("not an identifier").
     Such variables are not passed on, though.
chdir" reactivated (probably inherited from SunOS 4
     - Sun was involved in SVR4), but except for SunOS 5 not documented
`( )`
     (a sub-shell in cmd-substitution)
     might lock up the parent (SIGTTIN) after control returns to the parent.
     echo `(:)`
| [15] |  
     If you run an older shell without job control:
     Don't forget about nohup(1).
     However, background jobs are not in a new process group,
     which has again a strong influence on signal handling.
      | 
cat <<`...`" anymore
	     (and the backquotes are evaluated immediately)
	case x in in)" doesn't fail anymore with
	     syntax error
	/usr/ucb/ precedes /bin/, /usr/bin/
	     and /usr/5bin/.
	     SYSV3 is present in the environment
	     (labeled "SCO x86 compatibility support").
	type returns false on
	     "not found"
	EOF
	     aka <ctrl-d> 
	     but also upon "exit"
	getopts" in connection with a function might have looped
	set -e also affects commands on the same line again
		("set -e; false") (broken since SVR1)
	2>&1 program >/dev/null" doesn't redirect
	     stderr to /dev/null anymore.
	echo a > file1 b > file2"
	     fixed.
	<>" fixed and
	     documented (used in /etc/inittab f.i.).
	     IORDW (and O_RDWR) in the source,
	     it's missing in service.c, initio().
	IFS not inherited from environment anymore
	--" (end of options) becomes "-"
	     (undocumented since System III: turn off flags x and v)
	pfsh functionality added
	     (profiles for extended access control management)
             
	/tmp/sh{PID}{num}"),
	     num.
	test" knows "-L" (in addition
	     to "-h")
	
pfsh functionality removed)
read" knows SVR4.2-like "-r"
TIMEOUT" environment variable mechanism added (unit is minutes)
0600
umask" accepts the "-S" option (symbolic mode strings)
/usr/5bin:/bin:/usr/bin:"
	(for maximum SysV compatibility if the Heirloom toolchest is also installed)
PATH is unset) is
	"/bin:/usr/bin:" instead of ":/bin:/usr/bin"
ulimit" knows the flags "lmu" for portability
SHACCT (shell accounting) enabled
/usr/lib/locale 
cd" optionally available at compile time
hash -r" documented
snprintf() for "getopt"
realloc (no symptoms so far)
<EOF>" when exiting with EOF (ctrl-d)
    -version/--version/-V
    "alloc" allows to check the storage for corruption.
    /usr/ucb precedes /usr/bin in $PATH
    "f(){}; type f" prints "f() {f() { }}"
    sbrk() to malloc() based on the ideas from Geoff Collyer (see below)
    :" in $PATH might inhibit path search
    ": ${NAME=value}" works again on Linux/Cygwin
    "set -m" and "set -P" are documented
    "umask" implements the chmod(1) like symbolic notation to set and print (umask -S) the umask
    var2=val2 var1=val1) are avaluated from left to right now (SVR4.2MP, POSIX)
    "read VAR" auto-exports VAR after "set -a"
    "ulimit" implements -l, -m, -u for compatibility with *BSD and Linux
    "-version" is documented
    "getopts" (and its variables), "read", "test", "history" command (and the variables it uses)
    ${var-'$'} bug
    "f(){}; type f" bug introduced with 2012-03-30/Sun id 6776989
    "savehistory" and "map"
    
    "repeat" built-in added
    "cd" and "pwd" set $PWD
    pushd/popd/dirs" built-ins added
    times" produces POSIX compliant output
    repeat" fixed
    set -o ..." and "set +o ..." and
    alias, unalias
    type" doesn't know about aliases
    set -o globalaliases"
    dosh" added, behaves similar to "sh -c 'command'" without launching a new shell, supports aliases
    -i" option
    /etc/sh.shrc and $HOME/.shrc at startup, and implements $ENV (POSIX)
    "for i; do" and "for i;<newline> do" (see also the endnote in ${1+"$@"} and an austin group discussion)
    $PATH (introduced earlier by the sbrk() to malloc() conversion)
    type" knows about aliases
    sbrk() to malloc() conversion)
    -o aliasowner=name" allows for implementing su aliases
    argv[0]
    sbrk() to malloc() conversion,
	pfexec, ulimit options -l -m -u, SVR4.0 colon redirection bugfix, SVR3 ${var-'$'} bugfix,
	times output, avoid reading directories with the name of a script.
    aliasowner"
    $() command substitution (the only traditional bourne variant doing so)
    $(()) arithemtic expansion (the only traditional bourne variant doing so).
	break 0" bug from SVR2 fixed
    -o posix" implements a strict posix mode, as a few features are incomatible (e.g. accepting ^ as |)
    
get/setrlimit(2),
	 limit/unlimit" 
	with the flag "h" for hardlimit and the resources
	"cputime", "filesize", "datasize", "stacksize", "coredumpsize", "memoryuse" (rss), "descriptors", and "vmemory" (vsz)
	ulimit"
	with the flags "HSacdfnstv" for hard/softlimit, for print all, and for
	 the resources from above, except "memoryuse"
    test" knows -L and -l
         in addition to -h
    type" returns false on "not found"
    ${parameter##pattern} expansion, for the pattern "*/" only.
	/sbin/builtin_exec reads '${0##*/} "$@"'
	"POSIX shell builtin - cannot execute"
	alias", "unalias", "builtin_exec",
	"command" and "fc".
	/sbin on IRIX).
	IFS not inherited from environment anymore if running with setuid/gid or as root
    -p,
	PATH is unset) is "/usr/sbin:/usr/bsd:/bin:/usr/bin:"
    MAILCHECK (like default 600s) on start, instead of erroring out
    type" reports "priv" and "mldmode" as built-ins.Unknown builtin".
        UX:sh", "ERROR:",
            "WARNING", etc are
            contained in the binary, but not activated
            (contrary to the jsh(1) notes).
        
readt" built-in (timing out)
    TIMEOUT dynamic environment variable mechanism (unit is minutes)
    -p" removed,
         because privileges are handled differently in DG/UX
    UX:sh:" messages and
         thus seems to originate from between SVR4.0 and SVR4.2
    
UX:sh:" messages and
        might originate from between SVR4.0 and SVR4.2
   I" print a terse summary about
	resource usage
	of the current session after each command
        J" activate job control (like "m")
        E" EOF doesn't exit an interactive shell
        B" mimic BSD built-in compatibility (from SVR4)
	T" activate tilde expansion
	test" knows -L to check for symbolic links
   /usr/ucb/
	precedes /bin/ and /usr/bin/ in PATH.
   kill" doesn't accept a signal number/name in connection
	with a job id ("UX:kill: ERROR: Invalid tid or signal")
   type output
	for case in a function fixed
   /usr/net:/usr/bin:/usr/ucb"
    
[:lower:]",
	 including the equivalence and collation symbol,
	 "[[=c=]]" and "[[.cc.]]"
    suspend" sends SIGTSTOP
    type output
	 for case in a function fixed
    UX:sh: ERROR: ..."
     (years after the first definition in the SVID)
test" knows -L to check for symbolic links
type returns false on "not found"
mldmode" and "priv" built-ins 
a": variables set with "read" are also exported
TIMEOUT dynamic environment variable mechanism
     (the unit is seconds in contrast to minutes in other variants).
	The variable is readonly and set site-wide in /etc/default/sh.
LC_CTYPE nor LANG is set,
     then CHRCLASS is inspected (backwards compatibility)
LANG and LC_MESSAGES at run time
TFADMIN (for the "trusted facility management")
`( )` seems to be gone
read knows the flag -r
umask -S" knows the
     symbolic notation.  "Bad umask" error message added.
foo=`echo $bar` bar=text" results in foo being empty:
    "order of evaluation for variable assignments is changed to use
    left to right expansion rules."
    
| [16] | MP means maintenance pack | 
Stephen Bourne's talk (at BSDCan 2015) "Early days of Unix and design of sh" (youtube) with both enlightening and entertaining background about his shell.
See an interview with Steve Bourne (link to the australian Computerworld, '09).
See an article from John Mashey in net.unix-wizards ('86). By the way, the PWB (aka Mashey) shell from the Programmer's Workbench, about "PWB 1.0", is also archived by TUHS (see PDP-11/Distributions/usdl/).
See also an article by David Korn ('94) with an interesting second chapter concerning the Bourne shell history. 17
| [17] | The article mentions that functions were added to the Bourne shell in 1982. In the above interview Bourne tells that this was finished in 1983. The next release, SVR2, was published 1984. | 
 The Bourne shell would probably be in much wider interactive
use today, if it provided line editing (and a history mechanism).
 Having the above article in mind, this was - like with ksh originally -
probably not done in the hope that these features would move into the
terminal driver.
 Kenneth Almquist even 
intentionally released his ash without line
editing and history for this reasons.
 Louis Pouzin explains how the concept and name
of a "shell" was introduced in Multics in 1964/65.
 He was inspired by Christopher Strachey's macro-generator (and its quoting and passing of arguments).
 I don't know how much Bourne borrowed from this but it's an interesting connection to the re-parsing of expanded variables.
See manual pages of two main predecessors of the Bourne shell, the "Thompson" and the PWB shell:
< and >.
     Some comments
     
     from Norman Wilson (on the TUHS list).
^ and |.
     
     Dennis Ritchie about this (on his pages)
     
     and on the 
     TUHS list.
     
 See  Jeffrey A. Neitzel's pages
for both an enhanced, backward-compatible port of the Thompson shell and a
port of the original source, which compiles on current systems.
 As excellent illustration, you'll even find some
 example scripts there.
For more details about Version 6, see also a
V6 simh tape and an extensive V6 manual collection on
Wolfgang Helbig's pages,
or the software kit on the SIMH pages.
 Meanwhile the early Unix variants (research Unix until 7th
ed and 32V) have become available in source under a BSD-like
license
from SCO/Caldera.
 Have a look at TUHS,
i.e., the archive mirror site list (for complete distributions),
and the source code web interface (for a quick view at individual files).
For example the 7th edition source web interface is located here: minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh, for System III here, for Ultrix-3.1 here (v7-derived) and here (svr2-derived).
 You will not be able to easily compile earlier Bourne shells on a modern unix variant,
- because it is really oldfashioned C code with wild pointer management
- you cannot use libc because the shell internal memory management crashes malloc
which is also used libc-internally
- additionally, the methods for directory access have changed
 You can run Version 7 in an emulator like SIMH.
There's a also a V7 kit.
See also Hellwig Geisse's
pages about details how to get V7 running.
 With this V7 you can bootstrap a complete System III.
And here I was able to even compile the SVR1 and SVR2 shell.
An important advantage of running the complete system is having the related tools available.
You can even run the V7 shell natively, as port:
 Geoff Collyer provides
a source package
of the V7 shell (local copy,
patch to fix a compiling problem)
which should compile on most POSIX systems.
He has updated the memory management and directory-access code with parts
from his V9 shell.
However he has added a few minor modifications, so this
variant is not completely original. The visible differences are:
 He has also published
"a partial tour through
the unix shell" (local copy), which is quite helpful
if you want to get busy with the source.
 It emphasizes the memory management but also contains general hints.
 Nikola Vladov provides
an improved version of the above port.
He made the memory management completely robust, offers alternative versions,
and the shell is ready to be linked with dietlibc.
Additional visible differences to the original version are:
O_APPEND instead of seek()
O_NOFOLLOW
 There's also a FreeBSD port of the v7sh,
 however it incorporates also fixes from BSDs, Ultrix and System III
Running a recent Bourne shell:
 Thanks to the OpenSolaris project, Gunnar Ritter could publish
a source port of
a current Bourne shell as part of his Heirloom Toolchest.
 This was the first officially available up-to-date Bourne shell
on free unix flavours.
sbrk() vs. SEGVsbrk(2).
Some very informative details about the implementation are contained in Geoff Collyer's paper (see above), who rewrote the V7 sh memory management to run on later systems.
 <http://www.in-ulm.de/~mascheck/bourne/>