THE POSIX SHELL UNDER UNICOS 8
                      ______________________________
 
 

Introduction
------------

With UNICOS 8 the standard command and programming language shell is the POSIX
shell, i.e. /bin/sh is the POSIX shell, not the Bourne shell. The POSIX shell
is functionally equivalent to the Korn shell, so much so that at UNICOS 8 they
are one and the same binary i.e. file /bin/ksh is a link to file /bin/sh, and
both contain the binary for the POSIX shell. The Bourne shell is the default
shell under UNICOS 7, where file /bin/ksh contains the Korn shell binary and
file /bin/sh contains the Bourne shell binary. All Bourne shell scripts should
work unchanged under the POSIX shell, since the features of this shell are a
superset of those of the Bourne shell.

In the past users have generally used the Bourne shell for Batch work and the
C shell for Interactive work. This is because the Bourne shell, on UNICOS at
least, is more efficient than the C shell and allows redirection of the
standard error file. The C shell with its command history and "alias"
capabilities is more suited to interactive use. The Korn shell attempts to
incorporate, and in many ways improve upon, some of the useful C shell
features, while still allowing Bourne shell scripts to execute unchanged.

This article will mainly concentrate on the new features of the POSIX shell
over and above those provided by the Bourne shell. These include: command
history, command editing, tilde substitution, aliases, exporting of aliases
and functions, the "ENV" file, the ability to do integer arithmetic and to use
array variables, regular expressions and pattern-matching operators, the
"select" control structure, and extra shell variables and special built-in
commands.
 

Command History
---------------

The POSIX shell, like the C shell, keeps a record of the most recently typed
commands. The number of interactive commands recorded is determined by the
shell variable HISTSIZE, which, if not set, defaults to 128. A record of the
commands is kept in a file determined by the shell variable HISTFILE, which
if not set, defaults to $HOME/.sh_history, though on the Cray computers at
ECMWF this variable has been set to $TMPDIR/.sh_history. To list the last 16
commands input to the shell all you need to type is:

   history                             (or h, both are aliases for fc -l)

To see more history, just supply the amount as a negative number, e.g.

   h  -30
 

Command Editing
---------------

On the Cray computers at ECMWF the shell variable VISUAL has been set to
/usr/bin/vi. This means that while typing an interactive command it is
possible to correct errors by using the POSIX shell's built-in vi-like editor
(there is also a built-in emacs-like editor, though this will not be described
here). To enter the editor command mode you need to press the ESCAPE key. You
can then use many of the normal "vi" commands to correct the line of text, and
the press the RETURN key to execute the modified command. The "vi" commands
include:

   [count]h       to position 1 (or count) character(s) to the left
   [count]l       to position 1 (or count) character(s) to the right
          i       to insert text; press the ESCAPE key to terminate insert mode
   [count]x       to delete 1 (or count) character(s)
   [count]r       to replace 1 (or count) character(s)
         cw       to replace a word
          u       to undo the last modification
          U       to undo all modifications
          *       to do filename generation
          \       to do filename completion

While in editor command mode it is possible to abandon the command being
typed, and edit any of the commands in the history file. This is done again
by using standard "vi" commands, which include:

   [count]k       to fetch the previous (count) command
   [count]-       same as [count]k
   [count]j       to fetch the next (count) command
   [count]+       same as [count]j
   [count]G       to fetch command number count. If count is not specified
                  then it defaults to the least recent history command,
                  unlike in "vi" where G means the last line in the file.
   /string        to search backward in the history file for a previous
                  command containing string (less recent). string is
                  terminated by the RETURN key. If string is preceded by a
                  caret '^' then the matched command must begin with string.
   ?string        to search forward in the history file (more recent).

Another way of editing and re-executing commands from the history file is to
use the built-in command "fc". An alias is available, called "r" for "repeat",
which uses "fc". Some examples should make it easy to see how to use it:
 

   r                          this will repeat the previous command
   r 122                      this will repeat command number 122
   r cf                       this will repeat the last command beginning
                              with the string "cf"
   r abc=xyz                  this will repeat the last command, replacing
                              the string "abc" within the command by the
                              string "xyz"
   r lib="-l lib" cc          this will repeat the last command beginning
                              with the string "cc", replacing the string
                              "lib" within the command by the string "-l lib"
 

Tilde "~" Substitution
----------------------

Like the C shell, the POSIX shell allows you to specify a user's $HOME
directory by using the string "~userid". If userid is not a valid user
identifier then no substitution is performed. A ~ by itself or in front of a
/ is interpreted as the current user's $HOME directory. A ~ followed by a +
or - is interpreted as $PWD and $OLDPWD, respectively.
 

Aliases
-------

POSIX shell aliases are similar to, but different from, C shell aliases. The
syntax for defining them is different and they do not allow arguments. Aliases
can be exported to child processes and you can also set up "tracked" aliases,
this being the POSIX shell equivalent of the C shell hashing mechanism. The
format for defining an alias is:

   alias  [-t]  [-x]  name=command

The '-x' makes this an exported alias, and the "-t" makes it a tracked alias.
Without the "name=command" portion the command lists the aliases currently in
effect.

Aliases are frequently used as short forms for full path names. A tracked
alias has as part of its initial value the full path name of the command as
defined by the PATH variable and becomes undefined each time the PATH variable
is reset. The alias is tracked so that the next subsequent reference will
redefine the value. Aliases can be removed by using the special command:

   unalias  name

The following example shows how to set up and list some aliases:

   You type:                     Response:

   alias -x ls="ls -l "
   alias
                                 ls=ls -l
   alias -t dir="ls -CF "
   alias
                                 dir=ls -CF
                                 ls=ls -l
   alias -x
                                 ls=ls -l
   alias -t
                                 ls=/bin/ls
   PATH=$PATH:$HOME/bin
   alias -t
                                 none
 

Exporting Aliases and Functions and the "ENV" File
--------------------------------------------------

As mentioned above, aliases may be exported to POSIX shell child processes by
defining them with the "-x" option specified. Functions may be exported by
defining them and then using the "-f -x" options of the special command
"typeset" e.g.:

   cdls( )
   {
        cd     $1
        ls -la $1
   }
   typeset  -fx cdls

The  "typeset" special command has many uses and will be described later in
this article. The first line of the above function definition "cdls( )" is
similar to the way the C language defines a function; it could be replaced by
the more Fortran-like syntax "function cdls", which is equivalent.

Unless specified, aliases and functions, as with normal shell variables, are
not exported to child processes. To explore this further we will explain the
steps which are followed when the POSIX shell is invoked and shell scripts are
executed.

If your login shell is set to the POSIX shell, or if you run a batch job under
the default (POSIX) shell, then the following sequence of events takes place.

The file /etc/profile is read by the shell and the commands within this file
are executed. Next the file $HOME/.profile is read and the commands executed.
Usually $HOME/.profile has in it a reference to the file $HOME/.user_profile.
This file is also read and its commands executed. After this the POSIX shell
then checks the ENV shell variable, which by default on the ECMWF Cray
computers is set to /etc/sh_env. If it is set and the file it references is
readable then the shell executes the commands stored in the file.

/etc/profile is set up by ECMWF systems staff and contains commands to set up
such global shell variables as TERM - terminal type, DISPLAY - display console
name, ECLIB - the location of the eclib library, TEMP - the name of the user's
directory in /tmp etc.

$HOME/.profile is owned by the user and therefore can be modified by him.
However in general it should not be modified, as the next file is available for
that purpose.

$HOME/.user_profile is owned by the user and can be tailored by him to contain
any commands he wishes to execute automatically at login time or at the
beginning of batch job execution. This may be used to set up other global shell
variables, modify the PATH parameter, or set up private aliases and shell
functions, though these are better done in an "ENV" file.

/etc/sh_env is set up by ECMWF systems staff and this is the value of the ENV
shell variable. The file contains alias and function definitions which are
deemed to be useful for all users. There is a reference within this file to the
file $HOME/.sh_env. If this file exists and is readable then the commands
within it are also executed.

$HOME/.sh_env is owned by the user and can be tailored by him to contain any
private aliases and functions or global shell variables.

As can be seen there are quite a few files to read and execute. The "ENV" files
would appear to be surplus to requirements, but these files, /etc/sh_env and
$HOME/.sh_env are special in that not only are they read at login or start of
job time, but they are also read and the commands executed whenever a new shell
is invoked, whereas the various "profile" files are only read once. To see how
this matters we need to look at the steps involved when a new shell is invoked
and when a child shell is invoked.

If a script is executed by name then it normally runs as a forked process of
the current shell and all exported variables, aliases and functions are
available to this forked process. If the the script is run via the "sh" (or
"ksh") command, or if it has execute but not read permission, or if it has a
line saying "#!  /bin/sh" (or "/!  /bin/ksh") as its first record, then a new
shell (not a forked shell process) is started and although the exported
variables are available, the exported aliases and functions are not. However in
this case, commands in the file specified by the ENV variable are executed when
the new shell starts up. From this one can see that it is best to define
exported aliases and functions in the file $HOME/.sh_env, rather than in
$HOME/.user_profile, so that they are available to all subsequent scripts, not
just those executed by forked shell processes.

If you have a lot of shell functions, putting them in the $HOME/.sh_env file
becomes unwieldy. It may also affect the time it takes to start new shells, as
the file has to be read each time and the functions loaded. The command
"autoload function" circumvents these problems. "autoload" is a standard alias
for the ubiquitous "typeset" special command, the alias being
"autoload='typeset - fu'". This tells the shell that the function exists but is
undefined. When the POSIX shell encounters a reference to this function it then
searches the set of directories specified by the FPATH environment variable
(whose format is the same as PATH), for a file with the same name as the
function. This function is then loaded into the shell. If, for example, your
FPATH variable is set up in your $HOME/.user_profile as:

   FPATH="$HOME/sh_functions"

Then the first reference to any function specified on an "autoload" command
will cause the shell to look into the directory $HOME/sh_functions to see if a
file with the same name as the function exists. The function definition will
then be loaded into the shell and will be used directly from the shell from
then on. Initially this variable FPATH is set in /etc/sh_env to:

   FPATH="/usr/local/bin/sh_functions"

This directory contains some functions which are of general use and which are
defined as "autoload" functions in /etc/sh_env also. If you want to add your
own functions, it is suggested that you put each function definition in a
separate file in a directory called $HOME/sh_functions, define each function as
an "autoload" function (or if you wish them to be exported use: autoload -x) in
your $HOME/.sh_env file, and define the FPATH variable in your
$HOME/.user_profile file as

   FPATH="$FPATH:$HOME/sh_functions"

To see what functions are defined use the functions command (an alias for
typeset -f), and to delete a function definition use unset -f function. This
will erase the function from the shell's memory; however, autoloaded functions
are still remembered and any reference to one will cause it to be reloaded.

Functions help to simplify scripts by making them more modular. Since they
reside in the shell's memory (however see the description of autoloaded
functions above), they execute quickly and do not run as a separate process,
which is the case with script files. A function which has the same name as a
script or executable binary takes precedence over these. The command precedence
of the POSIX shell is:

         Keywords such as "if", "while", "else" etc.

         Aliases

         Built-in special commands such as "cd", "print", "set" etc.

         Functions

         Scripts and executable binaries
 

Integer Arithmetic and Array Variables
--------------------------------------

The ability to do integer arithmetic is provided by the POSIX shell with the
special command "let".  Constants are of the form [base#]n, where base is a
decimal number between 2 and 36 representing the arithmetic base and n is a
number in that base. base# is optional and if omitted then base 10 is assumed,
e.g. 16#1f is decimal 31 and 2#111 is 7.

An arithmetic expression uses the same syntax, precedence and associativity of
expression as in the C language. All integral operators, other than ++, - -, ?:
and , are supported, including +, -, *, /, %, >>, <<, !, ~, &, |, ^, &&, ||, >,
<, >=, <=, !=, ==, +=, -=, *=, /=, %=. Named parameters can be referenced by
name within an expression without using the parameter substitution ($) syntax.
When a named parameter is referenced, its value is evaluated as an arithmetic
expression, unless it has been specified to be of integer type using the "-i"
parameter of the "typeset" special command.

Because many of the arithmetic operators need quotation marks, to prevent them
from being interpreted by the shell, an alternative form of let " .... " is
available, in the form of (( .... )). The result of an arithmetic expression
can be obtained using the form $(( .... )). Do not confuse this with
$(command), which is analagous to using back-quotes (`) to substitute the
output produced by running command. One possible problem with using "let" or
"(( .... ))", which also exists with the expr command, is that an expression
which evaluates to 0 (zero) sets the shell status variable "$?" to a non-zero
value, which will abort the shell if the "set -e" command has been used.  This
problem does not occur with the "$(( ... )) construct. Some examples should
make this clearer.
 

   # Create a function to see if a value is an odd number
   # ----------------------------------------------------
   is_odd()
   {
   # Return TRUE status (0) if argument is an odd number
            ((($1 % 2) == 1))
   }

   # Show different ways of setting c to 4 and printing
   # --------------------------------------------------
   expand="(a + b)"
   typeset -i a=8#12
   b=2
   let "c = expand % 8"
   echo $c
            4
   ((c = expand % 8))
   echo $c
            4
   c=$((expand % 8))
   echo $c
            4
   echo $((expand % 8))
            4

   # Show how status depends on value and construct
   # ----------------------------------------------
   ((n = 1 + 1)) && print "n = $n, status = $?"
            n = 2, status = 0
   ((n = 1 - 1)) || print "n = $n, status = $?"
            n = 0, status = 1
   n=$((1 - 1)) && print "n = $n, status = $?"
            n = 0, status = 0

   # Obtain the time and print minutes since midnight
   # ------------------------------------------------
   hr=$(date +%H)
   mn=$(date +%M)
   sc=$(date +%S)
   secs=$((sc + 60 * ( mn + 60 * hr )))
   print $hr $mn $sc $secs
            15 21 04 55264

The POSIX shell supports the use of one dimensional array variables. Array
subscripts can be constants, variables or expressions in the range 0 to 1023.
Arrays need not be declared. Whole arrays can be assigned values using the "-
A" parameter of the special command "set", while individual elements can be
set as normal. Any reference to a named parameter with a valid subscript (0 -
 1023) is legal and an array will be created if necessary. Referencing an
array without a subscript is equivalent to referencing element 0 of the array.
For example, exporting array is equivalent to exporting array[0], i.e. only
the first element, not all elements of the array. To reference an array
element, other than in an expression, it is necessary to use the construct
${array[element]}.  The construct ${array[*]} or ${array[@]} gives the value
of each element separated by a space. The construct ${#array[*]} gives the
number of valid elements of array. A strange feature of POSIX shell arrays is
that if an array element has not been assigned, then it does not exist. If
this value were, for example, 4, then this would not necessarily mean that
elements 0, 1, 2 and 3 of the array existed, just that 4 elements in the range
0 to 1023 existed. Normally a script would be written to use consecutive
elements, starting at 0. Some examples should make this clearer:

   # Run 4 resolutions with associated "n" and "s" options
   # -----------------------------------------------------
   set -A nvals 1 22 53 75
   set -A svals 7 16 31 96
   set -A resolution T21 T63 T106 T213
   code[0]="OK - no problem"
   code[1]="ERROR - correct and rerun"

   n=0
   while [ $n -lt ${#resolution[*]} ]
   do
            ./run_spm -n ${nvals[$n]} -s ${svals[$n]} ${resolution[$n]}
            echo ${code[$?]}
            ((n += 1))
   done

   # Create a 10 element array of random numbers in range 0 - 31
   # -----------------------------------------------------------
   RANDOM=$$                           # set the random number generator seed
   integer i=0                         # integer is an alias for "typeset -i "
   while ((i < 10))                    # note - arithmetic expression used
   do
            ((ran[i] = RANDOM % 32))
            print "Random number $i = ${ran[$i]}"
            ((i += 1))
   done

   # Create a 3 element array with "funny" element numbers
   # -----------------------------------------------------
   odd_val[3]="value 0"
   odd_val[13]="value 13"
   odd_val[23]="value 23"
   echo "number of elements of odd_value = ${#odd_value[*]}"
            number of elements of odd_value = 3
   echo "number of characters in element 13 = ${#odd_val[13]}"
            number of characters in element 13 = 8
   echo "all = ${odd_val[@]}"              # @ is like * but preserves spaces
            all = value 0 value 13 value 23
 

Regular Expressions and Pattern-matching Operators
--------------------------------------------------

The POSIX shell, like the Bourne shell has the concept of "wildcard"
characters, (*, ? and [ ]).  However the POSIX shell goes much further, in that
it allows regular expressions to be used.  This gives it very powerful string
matching capabilities, similar to those of UNIX utilities such as awk(1),
egrep(1), sed(1) and others, although the syntax is different. In fact since
the shell allows extended regular expressions, it is more powerful in this
respect than "sed", which only allows normal regular expressions. Regular
expressions can be difficult to understand and it is beyond the scope of this
article to explain them.  The books mentioned at the end give detailed
explanations. A few simple examples are given here, just to show what may be
done:

   # Return a good status (0) if the argument contains only digits
   # -------------------------------------------------------------
   isnumber()
   {
            [[ $1 = +([0-9]) ]]
   }

   # Return a good status (0) if the argument contains only letters
   # -------------------------------------------------------------
   isalpha()                  # Return TRUE status if argument is a word
   {
            [[ $1 = +([a-zA-Z]) ]]
   }
 
   read data
   if isnumber  $data ; then
            print  $data is a number
   elif isalpha $data ; then
            if [[  $data = [A-Z]* ]] ; then
                     print "$data begins with an upper case letter"
            else
                     print "$data begins with a lower case letter"
            fi
   else
            print "$data is neither a number nor a word"
   fi

Notice in the above example that the test format used above is "if [[ condition
]]", rather than the old format "if [ condition ]". This new POSIX shell test
format allows regular expressions to be used on the right-hand side. The old
format does not allow regular expressions, but allows for Bourne shell
compatibility.

There are a set of pattern-matching operators #, ##, % and %%,which allow
patterns to be stripped from strings, contained within shell variables. The
classic use of these are to strip off components of pathnames. The operator
${variable#pattern} will, if pattern matches the beginning of the value of
variable, delete the shortest part that matches and return the rest. Operator
${variable##pattern} is similar, but this time deletes the longest part that
matches.  ${variable%pattern} and ${variable%%pattern} are also similar, but
this time the match is at the end of variable's value not the beginning. Again,
to learn more in detail about these consult one of the books listed below. The
following are examples of how they can be used:

   # Obtain the last element of a pathname (i.e. the filename)
   # ---------------------------------------------------------
   basename()                              # see basename(1)
   {
       print ${1##*/}                      # to remove all but the last element
   }

   # Obtain the directory part of a file's pathname
   # ----------------------------------------------
   dirname()                               # see dirname(1)
   {
       print ${1%/*}                       # to remove last element only
   }

   # For Fortran (.f) or C (.c) files return the object name (.o)
   # ------------------------------------------------------------
   objname()
   {
       print ${1%@(.f|.c)}.o               # to produce an object filename
   }

   SCRIPT=$(basename $0)
   for file in *.f *.c
   do
            if [[ $file = *.f ]] ; then
                     cf77 $file
            else
                     cc   $file
            fi
            print "$SCRIPT: SRC = $file, OBJ = $(objname $file)"
   done

Notice in this example that the "*.f" in the "for" statement expands to all
filenames in the current working directory which have a ".f" suffix". However
the "*.f" in the "if" statement does not. It is a regular expression and means
any pattern that ends with a ".f" suffix.
 

The "select" Control Structure
------------------------------

The "select" control structure provides a simple method for creating menus for
interactive scripts.  The shell sends menu items to the standard error file and
prompts the user for a selection. The structure is as follows:

   select identifier in words
   do
            commands
   done

Typically the words are the names of the menu items. Select presents each word
(which can be a phrase) preceded by a menu number and then prompts the user for
input. The prompt used is defined by shell variable PS3, which defaults to "#?"
if not set. If the user enters a number corresponding to one of the menu items,
the POSIX shell sets identifier to the word corresponding to that item number.
If the user presses the RETURN key without typing anything, the menu and prompt
are displayed again. If the user types something other than a menu number, the
identifier is set to null. The user's input is saved in the shell variable
REPLY so that if the user entered an invalid response it is possible to find
out what was typed.

A simple example should make this clear:

      PS3="Enter your selection: "
 
      echo "        COMMAND MENU \n"
 
      select choice in "Date & Time" "Users Logged-in" "Files" "Exit"
      do
         case $choice in
             "Date & Time")
                               date
                               ;;
             "Users Logged-in")
                               who
                               ;;
             "Files")
                               ls
                               ;;
             "Exit")
                               print "End of selection menu"
                               exit
                               ;;
             *)
                               echo "Invalid selection: $REPLY"
                               ;;
         esac
      done
 

Executing this produces the following:

                     COMMAND MENU
 
             1) Date & Time
             2) Users Logged-in
             3) Files
             4) Exit Menu
             Enter your selection: 1
             Tue May 10 07:43:33 GMT 1994
             Enter your selection: 4
             End of selection menu
 

New Shell Variables and Built-in Commands
-----------------------------------------

The POSIX shell has several new variables that can be used in scripts,
including:

ERRNO   The value of errno as set by the most recently failed system call.
LINENO  The number of the current line within the script or function being
        executed.
OLDPWD  The previous working directory set up by the cd command.
RANDOM  A random number, uniformly distributed between 0 and 32767.
REPLY   The input given to the select statement and to the read statement,
        when no arguments are supplied.
SECONDS The number of seconds that have elapsed since the shell was invoked.

New built-in commands include:

cd  [arg]
cd  old  new
             The first form is the "normal" change directory command, if arg
             is "-" then the directory is changed to the previous directory.
             In the the second form cd substitutes the string new for the
             string old in the current directory name and tries to change to
             this new directory.

fc  [-e ename]  [-n]  [-l]  [-r]  [first  [last] ]
fc  -e  -  [old=new]  [command]
             In the first form, a range of commands from first to last is
             selected from the last HISTSIZE commands that were typed at the
             terminal. The arguments first and last may be specified as a
             number or a string. A string is used to locate the most recent
             command beginning with the string. A negative number is used as
             an offset from the current command number. The "-l" flag causes
             the command(s) to be listed at the terminal. Otherwise the editor
             ename is invoked on a file containing these commands. If ename is
             not supplied then the value of FCEDIT is used. When editing is
             complete, the edited commands are executed. Flag "-r" reverses
             the order of the commands and "-n" omits the line numbers when
             listing them.

             In the second form the command, which can be a string or a
             number, is re-executed after the substitution old=new is
             performed (see earlier).

print  [-R]  [-n]  [-p]  [-r]  [-s]  [-u [n] ]  [arg ....]
             This is the shell output mechanism and can be used instead of
             echo(1). For more information see the manual page for ksh(1).
 

read  [-p]  [-r]  [-s]  [-u [n] ]  [name?prompt]  [name ....]
             This is the shell input mechanism. For more information see the
             manual page for ksh(1).

typeset  [±H]  [±L [n] ]  [±R [n] ]  [±Z [n] ]  [±f]  [±i [n] ]  [±l]  [±r]
         [±t]  [±u]  [±x]  [name[=value]]  ....
             This sets attributes and values for shell variables.
             Flag "-L" left justifies and removes leading blanks from value.
             If n is nonzero, it defines the width of the field, otherwise the
             first assignment determines the width. When name is assigned a
             value, it is filled with trailing blanks, or truncated if
             necessary. Leading zeros are removed if flag "-Z" is set.
             Flag "-R" right-justifies the field.
             Flag "-f" indicates that name is a function and no assignment may
             be specified. In this case the only other valid flags are "-t" to
             turn on tracing for the functions, "-u" to undefine (autoload)
             the function and "-x" to export the function.
             Flag "-i" specifies that name is an integer of base n.
             Flag "-l" converts all uppercase characters to lowercase.
             Flag "-u" converts all lowercase characters to uppercase.
             Flag "-r" specifies that name is read-only.
             Flag "-x" marks the given name(s), for automatic export to the
             environment of subsequently executed commands.
             Using a "+" instead of a "-" turns the flag off.

The following examples demonstrates some of these new commands:

             # Print (the number 12 in Decimal, Octal and Binary
             # -------------------------------------------------
             typeset -i8 octal_number
             typeset -i2 binary_number=12
             decimal_number=12
             octal_number=$decimal_number
             print "$decimal_number    $octal_number   $binary_number"
                      12    8#14    2#1100

             # Input a username, get the corresponding id and print both
             # ---------------------------------------------------------
             typeset -R10 username
             typeset -R6  id
             typeset -u   upper
             while :                             # Loop until "exit" is input.
             do
                      read uid?"Username? "
                      username="$uid"
                      upper="$uid"
                      if [ "$upper" = "EXIT" ] ; then
                               print "Finished"
                               break
                      fi
                      id=$(grep "^$uid:" /etc/passwd | cut -f3 -d:)
                      print "$username $id"
             done

                      Username? abc
                             abc    123
                      Username? vwxyz
                           vwxyz   1370
                      Username? Exit
                      Finished
 

Conclusion
----------

The POSIX shell has many new features over and above those of the Bourne shell.
It contains features which make it more suitable for interactive use than the C
shell. In essence there is now one shell which is suited both to interactive
and batch use and which will continue to run existing Bourne shell scripts.
However it is not downwardly compatible with the Bourne shell and any use in a
script of the new features described here will make that script unusable under
the Bourne shell, unless, of course, the system posesses a Korn shell, in which
case you should be able to prefix the script with a record stating "#!
/bin/ksh", causing the Bourne shell to start a Korn shell to execute the
script.

UNICOS 8 is running on the YMP-EL at ECMWF. It will also be the operating
system running on the YMP-2E/T3D machine and will eventually become the
production system on the C90.

To use the POSIX shell as described here you should copy the file
"/usr/local/src/public/profile" to the file "$HOME/.profile" and tailor
"$HOME/.user_profile" and "$HOME/.sh_env" to your requirements. You can print
the /etc/profile and /etc/sh_env files to see what has been set up by default
and you can print any of the files in /usr/local/bin/sh_functions to see what
functions are available. Under UNICOS 8 to make the POSIX shell your default
interactive shell you should use the command:

   chsh $USER /bin/sh

Although this article has concentrated on the POSIX shell under UNICOS 8, most
of this information also applies to the Korn shell, "/bin/ksh", under UNICOS 7
and under the IRIX operating system on the Silicon Graphics workstations at
ECMWF. The Korn shell is not available on the SUN workstations at ECMWF.

One slight problem with the Korn shell under UNICOS 7 is that it does not
support the "-S" flag of the "set" special command, whereas the POSIX shell
under UNICOS 8 does.

The purpose of this article is to show some of the new features that can be
used with the POSIX shell. It is not intended as a reference manual. To obtain
further information, read the "man" page for ksh(1), or better still, read one
of the books describing the Korn shell such as:

 "The Korn Shell User & Programming Manual" by Anatole Olczak (Addison-Wesley)
 "The Kornshell Command & Programming Language" by Morris I. Bolsky
         & David G. Korn
 "Learning the Korn Shell" by Bill Rosenblatt (O'Reilly & Associates)
 "A Practical Guide to Unix System V" by Mark G. Sobell (Benjamin/Cummings)
 
 

                                         - Neil Storer

           Original published in the ECMWF Newsletter, No. 66 (Summer 1994)
           Minor update (ATL):  10.08.94