------------------------------- Page    i -------------------------------

                    An Introduction to the UTS Shell




                                                 S. R. Bourne



                                                 Edited for UTS

------------------------------- Page   ii -------------------------------

                            TABLE OF CONTENTS


Abstract  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   1

1.    Introduction  . . . . . . . . . . . . . . . . . . . . . . . . .   1

1.1      Simple commands  . . . . . . . . . . . . . . . . . . . . . .   1
1.2      Background commands  . . . . . . . . . . . . . . . . . . . .   2
1.3      Input and output redirection . . . . . . . . . . . . . . . .   2
1.4      Pipelines and filters  . . . . . . . . . . . . . . . . . . .   3
1.5      File name generation . . . . . . . . . . . . . . . . . . . .   3
1.6      Quoting  . . . . . . . . . . . . . . . . . . . . . . . . . .   5
1.7      Prompting  . . . . . . . . . . . . . . . . . . . . . . . . .   5
1.8      The shell and login  . . . . . . . . . . . . . . . . . . . .   6

2.    Shell procedures  . . . . . . . . . . . . . . . . . . . . . . .   6

2.1      Control flow - for . . . . . . . . . . . . . . . . . . . . .   7
2.2      Control flow - case  . . . . . . . . . . . . . . . . . . . .   8
2.3      Here documents . . . . . . . . . . . . . . . . . . . . . . .  10
2.4      Shell variables  . . . . . . . . . . . . . . . . . . . . . .  11
2.5      The test command . . . . . . . . . . . . . . . . . . . . . .  14
2.6      Control flow - while . . . . . . . . . . . . . . . . . . . .  14
2.7      Control flow - if  . . . . . . . . . . . . . . . . . . . . .  15
2.8      Command grouping . . . . . . . . . . . . . . . . . . . . . .  17
2.9      Debugging shell procedures . . . . . . . . . . . . . . . . .  17
2.10     The man command  . . . . . . . . . . . . . . . . . . . . . .  18

3.    Keyword parameters  . . . . . . . . . . . . . . . . . . . . . .  19

3.1      Parameter transmission . . . . . . . . . . . . . . . . . . .  19
3.2      Parameter substitution . . . . . . . . . . . . . . . . . . .  20
3.3      Command substitution . . . . . . . . . . . . . . . . . . . .  21
3.4      Evaluation and quoting . . . . . . . . . . . . . . . . . . .  22
3.5      Error handling . . . . . . . . . . . . . . . . . . . . . . .  25
3.6      Fault handling . . . . . . . . . . . . . . . . . . . . . . .  26
3.7      Command execution  . . . . . . . . . . . . . . . . . . . . .  28
3.8      Invoking the shell . . . . . . . . . . . . . . . . . . . . .  30

References  . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  30

Appendix A.    Grammar  . . . . . . . . . . . . . . . . . . . . . . .  31

Appendix B.    Meta-characters and Reserved Words . . . . . . . . . .  33


                                                            Last Page  33

-------------------------------- Page  1 --------------------------------

                            TABLE OF FIGURES


Figure 1.    A version of the man command . . . . . . . . . . . . . .  19

Figure 2.    Quoting mechanisms . . . . . . . . . . . . . . . . . . .  24

Figure 3.    UTS signals  . . . . . . . . . . . . . . . . . . . . . .  26

Figure 4.    The touch command  . . . . . . . . . . . . . . . . . . .  27

Figure 5.    The scan command . . . . . . . . . . . . . . . . . . . .  28

-------------------------------- Page  2 --------------------------------

ABSTRACT

The shell is a command programming language that provides an interface to
the UTS operating system.  Its features include control-flow  primitives,
parameter passing, variables and string substitution.  Constructs such as
while, if then else, case  and for are available.  Two-way  communication
is possible between  the shell and  commands.  String-valued  parameters,
typically file names or flags, may be passed to a command.  A return code
is set by commands that  may be used to  determine control-flow, and  the
standard output from a command may be used as shell input.

The shell can modify the  environment in which  commands run.  Input  and
output can be redirected to files, and processes that communicate through
'pipes' can be invoked.  Commands  are found by searching directories  in
the file system in a sequence that can be defined  by the user.  Commands
can be read either from the terminal or from a file, which allows command
procedures to be stored for later use.




1.    INTRODUCTION

The shell is both a command language and a programming language that pro-
vides an interface to the UTS operating system.  This document describes,
with examples,  the UTS  shell.  The  first section  covers most  of  the
everyday requirements of terminal users.  Some familiarity with UTS is an
advantage when reading this section; see, for example, UTS for Beginners.
Section 2 describes those  features of the  shell primarily intended  for
use within shell procedures.  These  include the control-flow  primitives
and string-valued variables provided by the shell.  A knowledge of a pro-
gramming language would be a  help when reading  this section.  The  last
section describes the more advanced features of the shell.  References of
the form "see pipe(2)" are to an entry in the UTS Programmer's Manual.


1.1      SIMPLE COMMANDS

Simple commands consist of one  or more words  separated by blanks.   The
first word is the name of the command to be executed; any remaining words
are passed as arguments to the command.  For example,

          who

is a command that prints the names of users logged in.  The command

          ls -l

-------------------------------- Page  3 --------------------------------

prints a list of files in the  current directory.  The argument -l  tells
ls to print status information, size and the creation date for each file.


1.2      BACKGROUND COMMANDS

To execute a command the shell normally  creates a new process and  waits
for it to finish.  A command may be run without waiting for it to finish.
For example,

          cc pgm.c &

calls the C compiler  to compile the  file pgm.c.  The  trailing & is  an
operator that instructs the shell not to wait for the  command to finish.
To help keep track of such a process the shell reports its process number
following its  creation.  A  list of  currently active  processes may  be
obtained using the ps command.


1.3      INPUT AND OUTPUT REDIRECTION

Most commands produce output  on the standard  output which is  initially
the terminal.  This output may be sent to a file by writing, for example,

          ls -l >file

The notation >file is interpreted  by the shell and is  not passed as  an
argument to ls.  If file does not exist, then the  shell creates it; oth-
erwise the original contents of  file are replaced  with the output  from
ls.  Output may be appended to a file using the notation

          ls -l >>file

In this case, file is also created if it does not already exist.

The standard input of a command may be taken  from a file instead of  the
terminal by writing, for example,

          wc <file

The command wc reads  its standard  input (in this  case redirected  from
file) and prints  the number  of characters, words  and lines found.   If
only the number of lines is required then

          wc -l <file

could be used.

-------------------------------- Page  4 --------------------------------

1.4      PIPELINES AND FILTERS

The standard output of one command may be connected to the standard input
of another by using the 'pipe' operator, indicated by |, as in,

          ls -l | wc

Two commands connected in this way constitute a pipeline and the  overall
effect is the same as

          ls -l >file; wc <file

except that no file is used.  Instead the two processes are connected  by
a pipe (see pipe(2)) and  are run in parallel.  Pipes are  unidirectional
and synchronization is achieved by  halting wc when  there is nothing  to
read and halting ls when  the pipe is full.  The semicolon (;) is a  com-
mand separator allowing multiple commands to be entered on one line.

A filter is a  command that reads  its standard input,  transforms it  in
some way,  and  prints the  result  as output.   One such  filter,  grep,
selects from its input  those lines that  contain some specified  string.
For example,

          ls | grep old

prints those lines, if any, of the output from ls that contain the string
"old".  Another useful filter is sort.  For example,

          who | sort

will print an alphabetically sorted list of logged in users.

A pipeline may consist of more than two commands, for example,

          ls | grep old | wc -l

prints the number of file names  in the current directory containing  the
string "old".


1.5      FILE NAME GENERATION

Many commands accept arguments which are file names.  For example,

          ls -l main.c

prints information relating to the file main.c.

The shell provides a mechanism for generating  a list of file names  that
match a pattern.  For example,

-------------------------------- Page  5 --------------------------------

          ls -l *.c

generates, as arguments to ls,  all file names  in the current  directory
that end in .c.  The character * is a pattern  that will match any string
including the null string.  In  general, patterns  are specified as  fol-
lows.

     *      Matches any string of characters including the null string.

     ?      Matches any single character.

     [...]  Matches any one of the characters enclosed.  A pair of  char-
            acters separated by  a minus will  match any character  lexi-
            cally between the pair.

For example,

          [a-z]*

matches all names  in the  current directory  beginning with  one of  the
letters a through z.

          /usr/fred/test/?

matches all names in the directory /usr/fred/test that consist of a  sin-
gle character.  If no  file name is  found that matches the pattern  then
the pattern is passed, unchanged, as an argument.

This mechanism is useful both to save typing and to select names  accord-
ing to some pattern.  It may also be used to find files.  For example,

          echo /usr/fred/*/core

finds and  prints the  names  of all  core files  in  sub-directories  of
/usr/fred.  (echo is a  standard UTS command  that prints its  arguments,
separated by blanks.)  This last  feature can be  expensive, requiring  a
scan of all sub-directories of /usr/fred.

There is one  exception to  the general  rules given  for patterns.   The
character . at the start of a file name must be explicitly matched.

          echo *

will therefore echo all file names in the current directory not beginning
with '.'.

          echo .*

will echo all those file names that begin with '.'.  This avoids inadver-
tent matching of the names  . and ..  which mean 'the current  directory'

-------------------------------- Page  6 --------------------------------

and 'the  parent directory'  respectively.   (Notice that  ls  suppresses
information for the files '.' and '..'.)


1.6      QUOTING

Characters that have a special meaning to the shell, such as < > * ? | &,
are called metacharacters.  A complete list of metacharacters is given in
appendix B.  Any character preceded by a \ is quoted.  Quoted  characters
have their magical properties, if  any, turned off.  The \ is  suppressed
so that

          echo \?

will echo a single ?, and

          echo \\

will echo a single \.   To allow long strings to  be continued over  more
than one line the sequence \newline is ignored.

\ is convenient for quoting single characters.  When more than one  char-
acter needs quoting  the above  mechanism is clumsy  and error prone.   A
string of characters may be quoted by enclosing the string between single
quotes.  For example,

          echo xx'****'xx

will echo

          xx****xx

The quoted string may  not contain a  single quote but  may contain  new-
lines, which are preserved.   This quoting mechanism  is the most  simple
and is recommended for casual use.

A third  quoting mechanism  using double  quotes is  also available  that
prevents interpretation of some  but not all metacharacters.   Discussion
of the details is deferred to section 3.4.


1.7      PROMPTING

When the shell  is used from  a terminal  it will issue  a prompt  before
reading a command.  By default this prompt is '$ '.  It may be changed by
saying, for example,

          PS1=yesdear

that sets the prompt to be the string  "yesdear".  If a newline is  typed

-------------------------------- Page  7 --------------------------------

and further input is  needed then the  shell will issue the prompt  '> '.
Sometimes this can be caused by mistyping a  quote mark.  If it is  unex-
pected then an interrupt (PA1) will return the shell to read another com-
mand.  This prompt may be changed by saying, for example,

          PS2=more



1.8      THE SHELL AND LOGIN

Following login the shell is called to read and execute commands typed at
the terminal.  If the user has a .../profile file, then  it is assumed to
contain commands and is  read by  the shell before  reading any  commands
from the terminal.




2.    SHELL PROCEDURES

The shell may be used to read and  execute commands contained in a  file.
For example,

          sh file [args ...]

calls the shell to read commands from file.  Such a file is called a com-
mand procedure or shell  procedure.  Arguments may  be supplied with  the
call and are referred to in file using the positional parameters $1,  $2,
etc.  For example, if the file wg contains

          who | grep $1

then

          sh wg fred

is equivalent to

          who | grep fred


UTS files have  three independent  attributes, read,  write and  execute.
The UTS  command chmod(1) may  be used  to make a  file executable.   For
example,

          chmod +x wg

-------------------------------- Page  8 --------------------------------

will ensure that the  file wg  has execute status.   Following this,  the
command

          wg fred

is equivalent to

          sh wg fred

This allows shell procedures and programs to be used interchangeably.  In
either case a new process is created to run the command.

As well as providing names for  the positional parameters, the number  of
positional parameters in the  call is available  as $#.  The name of  the
file being executed is available as $0.

A special shell parameter  $* is  used to substitute  for all  positional
parameters except $0.  A typical  use of this is to provide some  default
arguments, as in,

          rm -f $*

which simply prepends some arguments to those already given.


2.1      CONTROL FLOW - FOR

A frequent use of shell procedures is to loop through the arguments  ($1,
$2, ...) executing commands once for each argument.  An example of such a
procedure is call that  searches the file  /etc/phone.book that  contains
lines of the form

          ...
          415/271-8281 Josephine Engineer ...
          408/314-1596 Joe Programmer ...
          ...

The text of call is

          for i
          do grep $i /etc/phone.book; done

The command

          call Joe

prints those lines in /etc/phone.book that contain the string "Joe".

          call Joe Josephine

-------------------------------- Page  9 --------------------------------

prints those lines containing "Joe" followed by those for "Josephine".

The for loop notation is recognized by the shell and has the general form

          for name in w1 w2 ...
          do command-list
          done

A command-list is a sequence of one or more simple commands separated  or
terminated by a newline  or semicolon.  Furthermore, reserved words  like
do and done are only recognized  following a newline or semicolon.   Name
is a shell variable that is set to the words w1 w2 ...  in turn each time
the command-list following do is executed.  If in w1 w2 ...  is  omitted,
then the loop is executed once for each positional parameter; that is, in
$* is assumed.

Another example of the use  of the for loop is  the create command  whose
text is

          for i do >$i; done

The command

          create alpha beta

ensures that two empty  files alpha and  beta exist and  are empty.   The
notation >file may be used on its own to create  or clear the contents of
a file.  Notice also  that a  semicolon (or newline)  is required  before
done.


2.2      CONTROL FLOW - CASE

A multiple way branch is provided for by the case notation.  For example,

          case $# in
               1) cat >> $1 ;;
               2) cat >> $2 <$1 ;;
               *) echo 'usage: append [ from ] to' ;;
          esac

is an append command.  When called with one argument as

          append file

$# is the string 1 and the standard input is copied onto the end of  file
using the cat command.

          append file1 file2

-------------------------------- Page 10 --------------------------------

appends the contents of  file1 onto  file2.  If the  number of  arguments
supplied to append is other  than 1 or 2 then a message is printed  indi-
cating proper usage.

The general form of the case command is

          case word in
               pattern) command-list ;;
               ...
          esac

The shell attempts to match word with each pattern, in the order in which
the patterns appear.  If a match is found, the associated command-list is
executed and execution of the case is  complete.  Since * is the  pattern
that matches any string it can be used for the default case.

A word of  caution: no  check is  made to  ensure that  only one  pattern
matches the case argument.  The first match found defines the set of com-
mands to be executed.  In  the example below  the commands following  the
second * will never be executed.

          case $# in
               *) ... ;;
               *) ... ;;
          esac


Another example of the  use of  the case construction  is to  distinguish
between different forms of an argument.  The following example is a frag-
ment of a cc command.

          for i
          do case $i in
               -[ocs]) ... ;;
               -*)     echo "unknown flag $i" ;;
               *.c)    /lib/c0 $i ... ;;
               *)      echo "unexpected argument $i" ;;
          esac
          done


To allow the same commands  to be associated with  more than one  pattern
the case command provides for alternative patterns separated by a |.  For
example,

          case $i in
               -x|-y)  ...
          esac

is equivalent to

-------------------------------- Page 11 --------------------------------

          case $i in
               -[xy])     ...
          esac


The usual quoting conventions apply so that

          case $i in
               \?)     ...

will match the character ?.


2.3      HERE DOCUMENTS

The shell procedure call in section 2.1 uses the file /etc/phone.book  to
supply the data for grep.  An alternative is to include  this data within
the shell procedure as a here document, as in,

          for i
          do grep $i <<!
          ...
          415/271-8281 Josephine Engineer ...
          408/314-1596 Joe Programmer ...
          ...
          !
          done

In this example the shell takes the lines between <<! and !  as the stan-
dard input for grep.  The string ! is arbitrary, the  document being ter-
minated by a line that consists of the string following <<.

Parameters are substituted in the document before it is made available to
grep as illustrated by the following procedure called edg.

          ed $3 <<%
          g/$1/s//$2/g
          w
          %

The call

          edg string1 string2 file

is then equivalent to the command

          ed file <<%
          g/string1/s//string2/g
          w
          %

-------------------------------- Page 12 --------------------------------

and changes all occurrences of string1 in file to string2.   Substitution
can be prevented using \ to quote the special character $ as in

          ed $3 <<+
          1,\$s/$1/$2/g
          w
          +

(This version of edg is equivalent to the first except that ed will print
a ? if there are no occurrences of the string  $1.) Substitution within a
here document  may  be  prevented entirely  by  quoting  the  terminating
string, for example,

          grep $i <<\#
          ...
          #

The document is  presented without  modification to  grep.  If  parameter
substitution is not required in a here document this latter  form is more
efficient.


2.4      SHELL VARIABLES

The shell provides string-valued variables.  Variable names begin with  a
letter and consist of letters, digits and underscores.  Variables may  be
given values by writing, for example,

          user=fred bin=box dept=4241

which assigns values to the variables user, bin and dept.  A variable may
be set to the null string by saying, for example,

          null=

The value of a variable is substituted by preceding its name with $;  for
example,

          echo $user

will echo "fred".

Variables may be  used interactively  to provide  abbreviations for  fre-
quently used strings.  For example,

          b=/usr/fred/bin
          mv pgm $b

will move  the file  pgm  from the  current directory  to  the  directory
/usr/fred/bin.  A more  general notation is  available for parameter  (or

-------------------------------- Page 13 --------------------------------

variable) substitution, as in,

          echo ${user}

which is equivalent to

          echo $user

and is used when  the parameter name  is followed by  a letter or  digit.
For example,

          tmp=/tmp/ps
          ps a >${tmp}a

will direct the output of ps to the file /tmp/psa, whereas,

          ps a >$tmpa

would cause the value of the variable tmpa to be substituted.

Except for $? the following  are set initially by the  shell.  $? is  set
after executing each command.

     $?    The exit status (return code) of the last command executed  as
           a decimal string.  Most commands return a zero exit status  if
           they complete successfully, otherwise  a non-zero exit  status
           is returned.  Testing the value of return codes is dealt  with
           later under if and while commands.

     $#    The number of positional parameters  (in decimal).  Used,  for
           example, in the append command to check the number of  parame-
           ters.

     $$    The process number of this shell (in decimal).  Since  process
           numbers are unique among  all existing processes, this  string
           is frequently used  to generate unique  temporary file  names.
           For example,

                     ps a >/tmp/ps$$
                     ...
                     rm /tmp/ps$$


     $!    The process number of the  last process run in the  background
           (in decimal).

     $-    The current shell flags, such as -x and -v.

Some variables have a special meaning to the shell and should be  avoided
for general use.

-------------------------------- Page 14 --------------------------------

     $MAIL When used interactively the shell looks at the file  specified
           by this variable before it issues a prompt.  If the  specified
           file has been modified since it  was last looked at the  shell
           prints the message  "you have mail"  before prompting for  the
           next command.   This variable  is typically  set in  the  file
           .../profile.  For example,

                     MAIL=/usr/mail/fred


     $HOME The default argument for the  cd command.  The current  direc-
           tory is used to resolve file name references that do not begin
           with a /, and is changed using the cd command.  For example,

                     cd /usr/fred/bin

           makes the current directory /usr/fred/bin

                     cat wn

           will print on the terminal the file wn in this directory.  The
           command cd with no argument is equivalent to

                     cd $HOME

           This variable is also  typically set in  the the user's  login
           profile.

     $PATH A list of directories that contain commands (the search path).
           Each time a command is executed by the shell a  list of direc-
           tories is searched for  an executable file.   If $PATH is  not
           set  then  the  current  directory,  /bin,  and  /usr/bin  are
           searched by default.   Otherwise $PATH  consists of  directory
           names separated by :.  For example,

                     PATH=:/usr/fred/bin:/bin:/usr/bin

           specifies that the current directory  (the null string  before
           the first  :),  /usr/fred/bin, /bin  and  /usr/bin are  to  be
           searched in that order.  In this way individual users can have
           their own 'private' commands that are accessible independently
           of the current directory.   If the command  name contains a  /
           then this directory search  is not used;  a single attempt  is
           made to execute the command.

     $PS1  The primary shell prompt string, by default, '$ '.

     $PS2  The shell prompt  when further  input is  needed, by  default,
           '> '.

-------------------------------- Page 15 --------------------------------

     $IFS  The set of characters used  by blank interpretation (see  sec-
           tion 3.4).


2.5      THE TEST COMMAND

The test command, although not part of the shell, is intended for use  by
shell programs.  For example,

          test -f file

returns zero exit status if file  exists and non-zero exit status  other-
wise.  In general test  evaluates a predicate  and returns the result  as
its exit status.  Some  of the  more frequently used  test arguments  are
given here, see test(1) for a complete specification.

          test s          true if s is not null
          test -f file    true if file exists
          test -r file    true if file is readable
          test -w file    true if file is writable
          test -d file    true if file is a directory



2.6      CONTROL FLOW - WHILE

The actions of the for  loop and the case branch  are determined by  data
available to the shell.  A while or until loop and an if then else branch
are also  provided  whose  actions  are determined  by  the  exit  status
returned by commands.  A while loop has the general form

          while command-list
          do command-list
          done


The value tested by the while command is the exit status of the last sim-
ple command following while.   Each time round  the loop command-list  is
executed; if a zero  exit status  is returned then  command-list is  exe-
cuted; otherwise, the loop terminates.  For example,

          while test $1
          do ...
               shift
          done

is equivalent to

          for i
          do ...

-------------------------------- Page 16 --------------------------------

          done

shift is a shell command that  renames the positional parameters $2,  $3,
... as $1, $2, ...  and loses $1.

Another kind of use for the while/until loop is to wait until some exter-
nal event occurs and then run some commands.  In an until loop the termi-
nation condition is reversed.  For example,

          until test -f file
          do sleep 300; done
          commands

will loop until file  exists.  Each time  round the loop  it waits for  5
minutes before trying again.  (Presumably another process will eventually
create the file.)


2.7      CONTROL FLOW - IF

Also available is a general conditional branch of the form,

          if command-list
          then command-list
          else command-list
          fi

that tests the value returned by the last simple command following if.

The if command may be used in conjunction  with the test command to  test
for the existence of a file as in

          if test -f file
          then    process file
          else    do something else
          fi


An example of the use of if, case and for constructions is given in  sec-
tion 2.10.

A multiple test if command of the form

          if ...
          then    ...
          else    if ...
                  then    ...
                  else    if ...
                          ...
                          fi

-------------------------------- Page 17 --------------------------------

                  fi
          fi

may be written using an extension of the if notation as,

          if ...
          then    ...
          elif    ...
          then    ...
          elif    ...
          ...
          fi


The following example is the touch command which changes the 'last  modi-
fied' time for a list  of files.  The command may be used in  conjunction
with make(1) to force recompilation of a list of files.

          flag=
          for i
          do case $i in
          -c) flag=N ;;
          *)  if test -f $i
              then    ln $i junk$$; rm junk$$
              elif test $flag
              then    echo file '$i' does not exist
              else    >$i
              fi
          esac
          done

The -c flag  is used  in this  command to  force subsequent  files to  be
created if they do  not already exist.   Otherwise, if the file does  not
exist, an error message is  printed.  The shell variable  flag is set  to
some non-null string if the -c argument is encountered.  The commands

          ln ...; rm ...

make a link to the file and then remove it thus causing the last modified
date to be updated.

The sequence

          if command1
          then    command2
          fi

may be written

          command1 && command2

-------------------------------- Page 18 --------------------------------

Conversely,

          command1 || command2

executes command2  only  if  command1  fails.  In  each  case  the  value
returned is that of the last simple command executed.


2.8      COMMAND GROUPING

Commands may be grouped in two ways,

          { command-list ; }

and

          ( command-list )


In the first, command-list is simply executed.  The second form  executes
command-list as a separate process.  For example,

          (cd x; rm junk)

executes rm junk in the directory  x without changing the current  direc-
tory of the invoking shell.

The commands

          cd x; rm junk

have the same effect but leave the invoking shell in the directory x.


2.9      DEBUGGING SHELL PROCEDURES

The shell provides two  tracing mechanisms to  help when debugging  shell
procedures.  The first is invoked within the procedure as

          set -v

(v for verbose) and causes lines of the  procedure to be printed as  they
are read.  It is useful to help isolate syntax errors.  It may be invoked
without modifying the procedure by saying

          sh -v proc ...

where proc is the name of the shell procedure.  This flag may be used  in
conjunction with the -n flag which prevents execution of subsequent  com-
mands.  (Note that saying set -n at  a terminal will render the  terminal

-------------------------------- Page 19 --------------------------------

useless until an end-of-file is typed.)

The command

          set -x

will produce an execution trace.   Following parameter substitution  each
command is printed as it is executed.  (Try these at  the terminal to see
what effect they have.) Both flags may be turned off by saying

          set -

and the current setting of the shell flags is available as $-.


2.10     THE MAN COMMAND

The following is the man command which is  used to print sections of  the
UTS Programmer's Manual.  It is called, for example, as

          man sh
          man 2 fork

In the first, the manual section for sh  is printed.  Since no volume  is
specified, volume 1 is used.   The second example prints the fork  manual
page from volume 2.



          cd /usr/man

          : 'colon is the comment command'
          : 'default is volume 1 ($v)'

          v=1
          for i
          do case $i in
          [1-3]) v=$i ;;
          *)     if test -f man$v/${i}.$v
                 then nroff -man man$v/${i}.$v
                 else
                      found=no
                      for j in 1 2 3
                      do if test -f man$j/${i}.$j
                           then
                                mn $j $i
                                found=yes
                           fi
                      done
                      case $found in

-------------------------------- Page 20 --------------------------------

                         no) echo "$i: manual page not found"
                      esac
                  fi
          esac
          done


                Figure 1.    A version of the man command




3.    KEYWORD PARAMETERS

Shell variables may be given  values by assignment or  when a shell  pro-
cedure is  invoked.   An  argument  to  a shell  procedure  of  the  form
name=value that precedes the command name causes value to be assigned  to
name before execution of the procedure begins.  The value of  name in the
invoking shell is not affected.  For example,

          user=fred command

will execute command with  user set to  fred.  The -k  flag to the  shell
causes arguments of  the form  name=value to be  interpreted in this  way
anywhere in the argument list.   Such names are sometimes called  keyword
parameters.  If any  arguments remain, they  are available as  positional
parameters $1, $2, etc.

The set command may also be used to set positional parameters from within
a procedure.  For example,

          set - *

will set $1 to the  first file name in the  current directory, $2 to  the
next, and so on.  Note that the first argument, -, ensures correct treat-
ment when the first file name begins with a -.


3.1      PARAMETER TRANSMISSION

When a shell procedure is invoked, both positional and keyword parameters
may be supplied with the  call.  Keyword parameters are also made  avail-
able implicitly to a shell procedure  by specifying in advance that  such
parameters are to be exported.  For example,

          export user bin

marks the variables user and bin for  export.  When a shell procedure  is

-------------------------------- Page 21 --------------------------------

invoked copies are made  of all exportable  variables for use within  the
invoked procedure.  Modification of such  variables within the  procedure
does not affect the values  in the invoking shell.  It is generally  true
of a shell  procedure that  it may  not modify  the state  of its  caller
without explicit  request  on  the  part of  the  caller.   (Shared  file
descriptors are an exception to this rule.)

Names whose  value  is  intended  to  remain  constant  may  be  declared
readonly.  The form  of this command is  the same as  that of the  export
command,

          readonly name ...

Subsequent attempts to set readonly variables are illegal.


3.2      PARAMETER SUBSTITUTION

If a shell parameter is not set then  the null string is substituted  for
it.  For example, if the variable d is not set

          echo $d

or

          echo ${d}

will echo nothing.  A default string may be given as in

          echo ${d-.}

which will echo the value of the variable d if  it is set and '.'  other-
wise.  The default string  is evaluated using  the usual quoting  conven-
tions so that

          echo ${d-'*'}

will echo * if the variable d is not set.  Similarly

          echo ${d-$1}

will echo the value of d if it is set and the value (if any) of $1 other-
wise.  A variable may be assigned a default value using the notation

          echo ${d=.}

which substitutes the same string as

          echo ${d-.}

-------------------------------- Page 22 --------------------------------

and if d were not previously set then it will  be set to the string  '.'.
(The notation ${...=...} is not available for positional parameters.)

If there is no sensible default then the notation

          echo ${d?message}

will echo the value of the variable d if it has one, otherwise message is
printed by the shell and  execution of the shell procedure is  abandoned.
If message is absent then  a standard message is  printed.  A shell  pro-
cedure that requires some parameters to be set might start as follows.

          : ${user?} ${dept?} ${bin?}
          ...

Colon (:) is a  command that is built  in to the  shell and does  nothing
once its arguments have  been evaluated.  If  any of the variables  user,
dept or bin are  not set, then  the shell will  abandon execution of  the
procedure.


3.3      COMMAND SUBSTITUTION

The standard output from a command can be substituted in a similar way to
parameters.  The command pwd  prints on its  standard output the name  of
the  current  directory.   For  example,  if  the  current  directory  is
/usr/fred/bin then the command

          d=`pwd`

is equivalent to

          d=/usr/fred/bin


The entire string between grave accents  (`...`) is taken as the  command
to be executed  and is replaced  with the output  from the command.   The
command is written using the  usual quoting conventions  except that a  `
must be escaped using a \.  For example,

          ls `echo "$1"`

is equivalent to

          ls $1

Command substitution occurs in all contexts where parameter  substitution
occurs (including here documents) and the treatment of the resulting text
is the same in both cases.  This mechanism allows string processing  com-
mands to be used within  shell procedures.  An example of such a  command

-------------------------------- Page 23 --------------------------------

is basename which removes a specified suffix from a string.  For example,

          basename main.c .c

will print the string "main".   Its use is  illustrated by the  following
fragment from a cc command.

          case $A in
               ...
               *.c)     B=`basename $A .c`
               ...
          esac

that sets B to the part of $A with the suffix .c stripped.

Here are some composite examples.

       *  for i in `ls -t`; do ...
          The variable i is set to the names of files in time order, most
          recent first.

       *  set `date`; echo $6 $2 $3, $4
          will print, e.g., 1977 Nov 1, 23:59:59


3.4      EVALUATION AND QUOTING

The shell is a macro processor that provides parameter substitution, com-
mand substitution and file name generation for the arguments to commands.
This section discusses the order in which these evaluations occur and the
effects of the various quoting mechanisms.

Commands are parsed initially according to the grammar given in  appendix
A.  Before a command is executed the following substitutions occur.

       *  parameter substitution, e.g. $user

       *  command substitution, e.g. `pwd`

          Only one evaluation occurs so  that if, for example, the  value
          of the variable X is the string "$y" then

                    echo $X

          will echo "$y".

       *  blank interpretation

          Following the above substitutions the resulting characters  are
          broken into non-blank words  (blank interpretation).  For  this

-------------------------------- Page 24 --------------------------------

          purpose 'blanks' are  the characters  of the  string $IFS.   By
          default, this string consists  of blank, tab and newline.   The
          null string is not regarded as a word unless it is quoted.  For
          example,

                    echo ''

          will pass on the  null string  as the first  argument to  echo,
          whereas

                    echo $null

          will call echo with no  arguments if the  variable null is  not
          set or set to the null string.

       *  file name generation

          Each word is then scanned for the file pattern characters *,  ?
          and [...] and an alphabetical  list of file names is  generated
          to replace the word.  Each such  file name is a separate  argu-
          ment.

The evaluations just described also occur in the list of words associated
with a for loop.   Only substitution occurs in  the word used for a  case
branch.

As well as the quoting mechanisms described  earlier using \ and '...'  a
third quoting mechanism is  provided using double quotes.  Within  double
quotes, parameter and command substitution  occurs but file name  genera-
tion and the interpretation of blanks does not.  The following characters
have a special meaning within double quotes and may be quoted using \.

          $    parameter substitution
          `    command substitution
          "    ends the quoted string
          \    quotes the special characters $ ` " \

For example,

          echo "$x"

will pass the  value of  the variable  x as  a single  argument to  echo.
Similarly,

          echo "$*"

will  pass  the  positional  parameters  as  a  single  argument  and  is
equivalent to

          echo "$1 $2 ..."

-------------------------------- Page 25 --------------------------------

The notation $@ is the same as $* except when it is quoted.

          echo "$@"

will  pass  the  positional  parameters,  unevaluated,  to  echo  and  is
equivalent to

          echo "$1" "$2" ...


The following table gives,  for each quoting  mechanism, the shell  meta-
characters that are evaluated.

          metacharacter
                \       $       *       `       "       '
          '     n       n       n       n       n       t
          `     y       n       n       t       n       n
          "     y       y       n       y       t       n

                t       terminator
                y       interpreted
                n       not interpreted



                     Figure 2.    Quoting mechanisms

In cases where  more than  one evaluation of  a string  is required,  the
built-in command eval may  be used.  For  example, if the variable X  has
the value "$y", and if y has the value "pqr" then

          eval echo $X

will echo the string "pqr".

In general the eval command evaluates its arguments (as do all  commands)
and treats the result as  input to the shell.  The input is read and  the
resulting command(s) executed.  For example,

          wg='eval who|grep'
          $wg fred

is equivalent to

          who|grep fred

In this example, eval  is required  since there is  no interpretation  of
metacharacters, such as |, following substitution.

-------------------------------- Page 26 --------------------------------

3.5      ERROR HANDLING

The treatment of  errors detected  by the shell  depends on  the type  of
error and on whether the shell is being used interactively.   An interac-
tive shell is one whose input and output are connected to a terminal  (as
determined by  gtty(2)).   A  shell invoked  with  the -i  flag  is  also
interactive.

Execution of a command (see also 3.7) may  fail for any of the  following
reasons.

  *  Input output redirection may fail.  For example, if a file does  not
     exist or cannot be created.

  *  The command itself does not exist or cannot be executed.

  *  The command terminates abnormally, for example, with a "page  trans-
     lation exception" or "segmentation  exception".  See Figure 2  below
     for a complete list of UTS signals.

  *  The command terminates normally but returns a non-zero exit status.

In all of these cases the shell will go  on to execute the next  command.
Except for the last case  an error message will be printed by the  shell.
All remaining errors cause the  shell to exit  from a command  procedure.
An interactive shell will return to read another command from  the termi-
nal.  Such errors include the following.

  *  Syntax errors.  e.g., if ... then ... done

  *  A signal such as interrupt.   The shell waits  for the current  com-
     mand, if any, to finish  execution and then either exits or  returns
     to the terminal.

  *  Failure of any of the built-in commands such as cd.

The shell flag -e causes the shell to terminate if any error is detected.

           1      hang up
           2      interrupt
           3*     quit
           4*     operation exception
           5      monitor call
           6      program event recording
           7*     page translation exception
           8*     floating divide exception
           9      kill - can't be caught or ignored
          10*     specification exception
          11*     segmentation exception
          12*     bad system call

-------------------------------- Page 27 --------------------------------

          13      end of pipe
          14      alarm clock
          15      soft kill
          16*     privileged operation exception
          17*     execute exception
          18*     protection exception
          19*     data exception
          20*     fixed point overflow exception
          21*     fixed point divide exception
          22*     decimal overflow exception
          23*     decimal divide exception
          24*     exponent overflow exception
          25*     exponent underflow exception
          26*     significance exception
          27      no space or inode on fs
          28      no file structures free in system
          29      program initiation
          30      svc interrupt
          31      time slice end

                        Figure 3.    UTS signals

Those signals marked with an asterisk produce a core dump if not  caught.
A core dump  is taken  only if a  file named core  exists in the  current
directory.  However,  the shell  itself ignores  quit which  is the  only
external signal  that can  cause a  dump.  The  signals in  this list  of
potential interest to shell programs are 1, 2, 3, 14 and 15.


3.6      FAULT HANDLING

Shell procedures normally terminate  when an interrupt  is received  from
the terminal.  The trap command is used if some cleaning  up is required,
such as removing temporary files.  For example,

          trap 'rm /tmp/ps$$; exit' 2

sets a trap  for signal  2 (terminal interrupt),  and if  this signal  is
received will execute the commands

          rm /tmp/ps$$; exit

Exit is another  built-in command  that terminates execution  of a  shell
procedure.  The  exit is  required; otherwise,  after the  trap has  been
taken, the shell will resume executing  the procedure at the place  where
it was interrupted.

UTS signals can be handled in one of three ways.  They can be ignored, in
which case the signal is never sent to the process.   They can be caught,
in which case the process must decide what action to take when the signal

-------------------------------- Page 28 --------------------------------

is received.  Lastly, they can  be left to cause termination of the  pro-
cess without it having to take any further action.  If a signal is  being
ignored on entry to the  shell procedure, for example, by invoking it  in
the background (see 3.7) then trap commands (and the signal) are ignored.

The use of trap is illustrated by this modified version of the touch com-
mand (Figure 4).  The cleanup action is to remove the file junk$$.

          flag=
          trap 'rm -f junk$$; exit' 1 2 3 15
          for i
          do case $i in
               -c) flag=N ;;
               *) if test -f $i
                  then    ln $i junk$$; rm junk$$
                  elif    test $flag
                  then    echo file '$i' does not exist
                  else    > $i
                  fi
          esac
          done


                     Figure 4.    The touch command

The trap command appears before the creation of the temporary file;  oth-
erwise it would be possible  for the process to die without removing  the
file.

Since there is no signal 0 in UTS it is used by the shell to indicate the
commands to be executed on exit from the shell procedure.

A procedure may, itself, elect to  ignore signals by specifying the  null
string as the argument to trap.  The following fragment is taken from the
nohup command.

          trap '' 1 2 3 15

which causes hangup, interrupt, quit and kill  to be ignored both by  the
procedure and by invoked commands.

Traps may be reset by saying

          trap 2 3

which resets the traps for  signals 2 and 3 to  their default values.   A
list of the current values of traps may be obtained by writing

          trap

-------------------------------- Page 29 --------------------------------

The procedure scan  (Figure 5) is  an example  of the use  of trap  where
there is no exit in  the trap command.  Scan takes each directory in  the
current directory,  prompts with  its name,  and then  executes  commands
typed at the terminal until  an end of file or an interrupt is  received.
Interrupts are ignored while executing  the requested commands but  cause
termination when scan is waiting for input.

          d=`pwd`
          for i in *
          do if test -d $d/$i
               then cd $d/$i
                    while echo "$i:"
                         trap exit 2
                         read x
                    do trap : 2; eval $x; done
               fi
          done


                      Figure 5.    The scan command

Read x is a built-in command that reads one line from the standard  input
and places  the result in  the variable  x.  It returns  a non-zero  exit
status if either an end-of-file is read or an interrupt is received.


3.7      COMMAND EXECUTION

To run a command (other  than a built-in) the shell  first creates a  new
process using the system  call fork.  The  execution environment for  the
command includes input, output and  the states of  signals, and is  esta-
blished in the child process before the command is executed.   The built-
in command exec is used  in the rare cases when  no fork is required  and
simply replaces the shell with a new command.  For example, a simple ver-
sion of the nohup command looks like

          trap '' 1 2 3 15
          exec $*

The trap turns off the signals specified so that they are ignored by sub-
sequently created commands  and exec  replaces the shell  by the  command
specified.

Most forms of input output  redirection have already been described.   In
the following, word is  only subject to  parameter and command  substitu-
tion.  No file  name generation  or blank interpretation  takes place  so
that, for example,

          echo ... >*.c

-------------------------------- Page 30 --------------------------------

will write  its output  into a  file  whose name  is *.c.   Input  output
specifications are evaluated left to right as they appear in the command.

> word    The standard output  (file descriptor  1) is sent  to the  file
          word which is created if it does not already exist.

>> word   The standard output is sent to  file word.  If the file  exists
          then output is appended (by seeking to the end); otherwise  the
          file is created.

< word    The standard input (file descriptor  0) is taken from the  file
          word.

<< word   The standard input is taken from the lines of shell input  that
          follow up to but not including a line consisting only  of word.
          If word  is  quoted  then no  interpretation  of  the  document
          occurs.  If word is not quoted then parameter and command  sub-
          stitution occur and \ is used to quote the characters \ $ ` and
          the first character of  word.  In the  latter case \newline  is
          ignored (c.f. quoted strings).

>& digit  The file descriptor digit  is duplicated using the system  call
          dup(2) and the result is used as the standard output.

<& digit  The standard input is duplicated from file descriptor digit.

<&-       The standard input is closed.

>&-       The standard output is closed.

Any of  the above  may be  preceded by  a digit  in which  case the  file
descriptor created is that specified by the digit instead of  the default
0 or 1.  For example,

          ... 2>file

runs a command with message output (file descriptor 2) directed to file.

          ... 2>&1

runs a  command  with its  standard  output and  message  output  merged.
(Strictly speaking  file  descriptor 2  is  created by  duplicating  file
descriptor 1 but the effect is usually to merge the two streams.)

The environment for a command run in the background such as

          pr *.c | opr &

is modified in two ways.  Firstly, the default standard input for such  a
command is the empty  file /dev/null.  This  prevents two processes  (the

-------------------------------- Page 31 --------------------------------

shell and the command),  which are  running in parallel,  from trying  to
read the same input.  Chaos  would ensue if this were not the case.   For
example,

          ed file &

would allow both the editor and the shell to read from the same input  at
the same time.

The other modification to the environment  of a background command is  to
turn off the QUIT and  INTERRUPT signals so that they are ignored by  the
command.  This allows these signals  to be used  at the terminal  without
causing background commands to terminate.  For this reason, the UTS  con-
vention for a signal is that if it is set to 1 (ignored) then it is never
changed even for a short  time.  Note that the shell command trap has  no
effect for an ignored signal.


3.8      INVOKING THE SHELL

The following flags are interpreted by the shell when it is invoked.   If
the first character of argument  zero is a minus, then commands are  read
from the file .../profile.

-c string
     If the -c flag is present, then commands are read from string.

-s   If the -s flag is present or  if no arguments remain, then  commands
     are read from the standard  input.  Shell output is written to  file
     descriptor 2.

-i   If the -i  flag is  present or  if the  shell input  and output  are
     attached to a terminal (as told by gtty) then this shell is interac-
     tive.  In this case TERMINATE  is ignored (so that  kill 0 does  not
     kill an interactive shell) and  INTERRUPT is caught and ignored  (so
     that wait is interruptable).  In  all cases QUIT  is ignored by  the
     shell.




REFERENCES

 [1]  UTS for Beginners.

 [2]  UTS Programmer's Manual.

-------------------------------- Page 32 --------------------------------

APPENDIX A.    GRAMMAR

item:           word
                input-output
                name = value

simple-command: item
                simple-command item

command:        simple-command
                ( command-list )
                { command-list }
                for name do command-list done
                for name in word ... do command-list done
                while command-list do command-list done
                until command-list do command-list done
                case word in case-part ... esac
                if command-list then command-list else-part fi

pipeline:       command
                pipeline | command

andor:          pipeline
                andor && pipeline
                andor || pipeline

command-list:   andor
                command-list ;
                command-list &
                command-list ; andor
                command-list & andor

input-output:   > file
                < file
                >> word
                << word

file:           word
                & digit
                &-

case-part:      pattern) command-list ;;

pattern:        word
                pattern | word

else-part:      elif command-list then command-list else-part
                else command-list
                empty

-------------------------------- Page 33 --------------------------------

empty:

word:           a sequence of non-blank characters

name:           a sequence of letters, digits or underscores
                starting with a letter

digit:          0 1 2 3 4 5 6 7 8 9

-------------------------------- Page 34 --------------------------------

APPENDIX B.    META-CHARACTERS AND RESERVED WORDS

a) syntactic
     |       pipe symbol
     &&      'andf' symbol
     ||      'orf' symbol
     ;       command separator
     ;;      case delimiter
     &       background commands
     ( )     command grouping
     <       input redirection
     <<      input from a here document
     >       output creation
     >>      output append


b) patterns
     *       match any character(s) including none
     ?       match any single character
     [...]   match any of the enclosed characters


c) substitution
     ${...}  substitute shell variable
     `...`   substitute command output


d) quoting
     \       quote the next character
     '...'   quote the enclosed characters except for '
     "..."   quote the enclosed characters except for $ ` \ "


e) reserved words
          if then else elif fi
          case in esac
          for while until do done
          {  }
