










      sIntroduction to [1mksh‐93                       dat[22mDecember 21, 1993
       [1mCharge Case 311466‐6713[0m
       [1mFile Case 61175                              fro[22mDavid G. Korn
                                                       MH 11267
                                                       3C‐526B x7975
                                                       (research!dgk)

                                                       TM

                           [4mMEMORANDUM[24m [4mFOR[24m [4mFILE[0m

       [4m1.[24m  [4mINTRODUCTION[0m

       The term "shell" is used to describe a program that provides
       a command language interface.   Because  the  UNIX*   system
       shell is a user level program, and not part of the operating
       system itself, anyone can write a new  shell  or  modify  an
       existing  one.   This has caused an evolutionary progress in
       the design and implementation of  shells,  with  the  better
       ones  surviving.   The  most  widely  available  UNIX system
       shells are the Bourne shell[7], written by Steve  Bourne  at
       AT&T  Bell Laboratories, the C shell[8], written by Bill Joy
       at the University of California, Berkeley, and the KornShell
       language   [9],   written   by   David  Korn  at  AT&T  Bell
       Laboratories.  The Bourne shell is available on  almost  all
       versions  of the UNIX system.  The C Shell is available with
       all Berkeley Software Distribution (BSD) UNIX systems and on
       many  other systems.  The KornShell is available on System V
       Release 4 systems.  In addition, it  is  available  on  many
       other  systems.   The  source  for the KornShell language is
       available from the AT&T Toolchest,  an  electronic  software
       distribution  system.   It runs on all known versions of the
       UNIX system and on many UNIX system look‐alikes.

       There have been several articles comparing the  UNIX  system
       shells.    Jason  Levitt[10]  highlights  some  of  the  new
       features  introduced  by  the  KornShell   language.    Rich
       Bilancia[11]  explains  some  of the advantages of using the
       KornShell language.  John Sebes[12] provides a more detailed
       comparison  of  the three shells, both as a command language
       and as a programming language.

       The KornShell language is a superset of  the  Bourne  shell.
       The  KornShell  language  has  many  of  the popular C shell
       features, plus additional features of its own.  Its  initial
       popularity  stems  primarily  from  its  improvements  as  a
       command language.  The primary interactive  benefit  of  the

       ____________________

       *  UNIX is a registered trademark of USL




       KornShell  command  language is a visual command line editor
       that allows you to make corrections to your current  command
       line  or  to earlier command lines, without having to retype
       them.

       However, in  the  long  run,  the  power  of  the  KornShell
       language  as a high‐level programming language, as described
       by Dolotta and  Mashey[13],  may  prove  to  be  of  greater
       significance.   [1mksh‐93  [22mprovides  the  programming  power of
       several other interpretive languages such as [1mawk[22m, [1mFIT[22m, [1mPERL[22m,
       and  [1mtcl[22m.  An application that was originally written in the
       C  programming  language  was  rewritten  in  the  KornShell
       language.   More  than  20,000 lines of C code were replaced
       with KornShell scripts totaling fewer than  700  lines.   In
       most  instances  there  was  no  perceptible  difference  in
       performance between the two versions of the code.

       The KornShell language  has  been  embedded  into  windowing
       systems  allowing  graphical user interfaces to be developed
       in shell rather than having to build applications that  need
       to  be  compiled.  The [1mwksh [22mprogram[14] provides a method of
       developing OpenLook or Motif applications as [1mksh [22mscripts.

       This memo is an introduction to  [1mksh‐93[22m,  the  program  that
       implements  an  enhanced  version of the KornShell language.
       It is referred to as [1mksh [22min the rest of this memo.  The memo
       describes  the  KornShell  language based on the features of
       the 12/28/93 release of [1mksh[22m.  This memo is not  a  tutorial,
       only  an  introduction.  The second edition of reference [9]
       gives a more complete treatment of the KornShell language.

       A concerted effort has been made to achieve  both  System  V
       Bourne  shell  compatibility and IEEE POSIX compatibility so
       that scripts written for either  of  these  shells  can  run
       without modification with [1mksh[22m.  In addition, [1mksh‐93 [22mattempts
       to be compatible with older versions of [1mksh[22m.  When there are
       conflicts  between versions of the shell, [1mksh‐93 [22mselects the
       behavior  dictated  by  the  IEEE   POSIX   standard.    The
       description of features in this memo assumes that the reader
       is already familiar with the Bourne shell.


       [4m2.[24m  [4mCOMMAND[24m [4mLANGUAGE[0m

       There is no separate command language.  All features of  the
       language,  except  job  control,  can  be used both within a
       script and interactively from a terminal.  However, features
       that  are  more  likely  to  be  used while running commands
       interactively from a terminal are presented here.

       [4m2.1[24m  [4mSetting[24m [4mOptions[0m

       By convention, UNIX  commands  consist  of  a  command  name
       followed by options and other arguments.  Options are either
       of the form [1m‐[4m[22mletter[24m, or [1m‐[4m[22mletter[24m [4mvalue[24m.  In the former  case,
       several  options  may  be  grouped  after  a  single [1m‐[22m.  The
       argument [1m‐‐ [22msignifies an end to the option list and is  only
       required when the first non‐option argument begins with a [1m‐[22m.
       Most commands print  an  error  message  which  shows  which
       options  are  permitted  when given incorrect arguments.  In
       addition, the option sequence [1m‐?  [22mcauses  most  commands  to





       print a usage message which lists the valid options.

       Ordinarily, [1mksh [22mexecutes a command by using the command name
       to locate a program to run and by running the program  as  a
       separate  process.  Some commands, referred to as [4mbuilt‐ins[24m,
       are carried out by [1mksh [22mitself, without creating  a  separate
       process.   The  reasons  that some commands are built‐in are
       presented  later.   In  nearly  all  cases  the  distinction
       between  a  command  that is built‐in and one that is not is
       invisible to the user.  However, nearly  all  commands  that
       are built‐in follow command line conventions.

       [1mksh  [22mhas  several  options  that  can  be set by the user as
       command line arguments at invocation and as option arguments
       to  the  [1mset  [22mcommand.  Most other options can be set with a
       single letter option or  as  a  name  that  follows  the  [1m‐o[0m
       option.   Use [1mset ‐o [22mto display the current option settings.
       Some of these options, such as [1minteractive [22mand [1mmonitor  [22m(see
       [4mJob[24m  [4mControl[24m  below),  are enabled automatically by [1mksh [22mwhen
       the shell is connected to a terminal device.  Other options,
       such  as  [1mnoclobber  [22mand [1mignoreeof[22m, are normally placed in a
       startup file.  The [1mnoclobber [22moption causes [1mksh [22mto  print  an
       error  message  when  you use [1m> [22mto redirect output to a file
       that already exists.  If you want to redirect to an existing
       file,  then  you  have  to  use [1m>| [22mto override the [1mnoclobber[0m
       option.  The [1mignoreeof [22moption is used to prevent the [4mend‐of‐[0m
       [4mfile[24m  character,  normally [1m^D [22m(Control‐ d), from exiting the
       shell and possibly logging you out.  You must type  [1mexit  [22mto
       log  out.  Most of the options are described in this memo as
       appropriate.

       [4m2.2[24m  [4mCommand[24m [4mAliases[0m

       Command aliases provide a mechanism of associating a command
       name and arguments with a shorter name.  Aliases are defined
       with the [1malias [22mbuilt‐in.   The  form  of  an  [1malias  [22mcommand
       definition is:
                             [1malias [4m[22mname[24m[1m=[4m[22mvalue[0m
       As  with  most  other shell assignments, no space is allowed
       before or after the [1m=[22m.  The  characters  of  an  alias  name
       cannot  be  characters  that  are special to the shell.  The
       replacement string,  [4mvalue,[24m  can  contain  any  valid  shell
       script,  including  meta‐characters such as pipe symbols and
       i/o‐redirection provided that they are quoted.  Unlike  [1mcsh[22m,
       aliases  in  [1mksh  [22mcannot  take  arguments.   The  equivalent
       functionality of aliases with arguments can be achieved with
       shell functions, described later.

       As  a  command  is  being  read, the command name is checked
       against a list of [4malias[24m names.  If it is found, the name  is
       replaced  by  the  alias value associated with the [4malias[24m and
       then rescanned.  When rescanning the  value  for  an  alias,
       alias  substitutions  are performed except for an alias that
       is currently being processed.  This prevents infinite  loops
       in  alias  substitutions.   For  example  with  the aliases,
       [1malias l=ls ’ls=ls ‐C’[22m, the command name [1ml [22mbecomes [1mls[22m,  which
       becomes  [1mls ‐C[22m.   Ordinarily,  only the command name word is
       processed for alias substitution.  However, if the value  of
       an  alias ends in a space, then the word following the alias
       is also checked  for  alias  substitution.   This  makes  it
       possible to define an alias whose first argument is the name





       of a command and have alias substitution performed  on  this
       argument, for example [1mnohup=’nohup ’[22m.

       Aliases  can  be  used to redefine built‐in commands so that
       the alias,
                            [1malias test=./test[0m
       can be used  to  look  for  [1mtest  [22min  your  current  working
       directory  rather  than  using  the  built‐in  [1mtest [22mcommand.
       Reserved words such as [1mfor [22mand [1mwhile [22mcannot  be  changed  by
       aliasing.  The command [1malias[22m, without arguments, generates a
       list of aliases and corresponding alias values.  The [1munalias[0m
       command removes the name and text of an alias.

       Aliases  are  used to save typing and to improve readability
       of scripts.  Several aliases are  predefined  by  [1mksh[22m.   For
       example, the predefined alias
                        [1malias integer=’typeset ‐i’[0m
       allows  the  integer  variables  [1mi  [22mand [1mj [22mto be declared and
       initialized with the command
                             [1minteger i=0 j=1[0m

       While  aliases  can  be  defined  in  scripts,  it  is   not
       recommended.   The  location  of  an  alias  command  can be
       important since aliases are only processed when a command is
       read.   A  [1m.   [22mprocedure (the shell equivalent of an include
       file) is read all at once (unlike start up files  which  are
       read  a command at a time) so that any aliases defined there
       will not effect any commands within this script.  Predefined
       aliases do not have this problem.

       [4m2.3[24m  [4mCommand[24m [4mRe‐entry[0m

       When run interactively, [1mksh [22msaves the commands you type at a
       terminal in a file.  If the variable [1mHISTFILE [22mis set to  the
       name  of a file to which the user has write access, then the
       commands are stored in this  [4mhistory[24m  file.   Otherwise  the
       file  [1m$HOME/.sh_history  [22mis  checked for write access and if
       this fails an unnamed file  is  used  to  hold  the  history
       lines.    Commands   are   always  appended  to  this  file.
       Instances of [1mksh [22mthat run  concurrently  and  use  the  same
       history  file name, share access to the history file so that
       a command entered in one shell will be available for editing
       in  another  shell.   The  file  may  be  truncated when [1mksh[0m
       determines that no other shell is using  the  history  file.
       The  number of commands accessible to the user is determined
       by the value of the [1mHISTSIZE [22mvariable at the time the  shell
       is  invoked.   The  default  value is 256.  Each command may
       consist of one or more lines since  a  compound  command  is
       considered  one  command.   If  the  character  [1m!  [22mis placed
       within the [4mprimary[24m [4mprompt[24m string, [1mPS1[22m, then it  is  replaced
       by the command number each time the prompt is given.

       A  built‐in  command  named [1mhist [22mis used to list and/or edit
       any of these saved commands.   The  option  [1m−l  [22mis  used  to
       specify  listing  of  previous  commands.   The  command can
       always be specified with a range of one  or  more  commands.
       The  range  can  be  specified by giving the command number,
       relative or absolute, or by giving the  first  character  or
       characters  of  the  command.  When given without specifying
       the range, the last 16 commands are listed, each preceded by
       the command number.






       If  the  listing  option  is not selected, then the range of
       commands specified, or the  last  command  if  no  range  is
       given,  is  passed  to  an  editor  program before being re‐
       executed by [1mksh[22m.  The editor to be  used  may  be  specified
       with  the  option  [1m−e [22mand following it with the editor name.
       If this option is not specified,  the  value  of  the  shell
       variable  [1mHISTEDIT  [22mis  used  as  the  name  of  the editor,
       providing that this variable has a non‐null value.  If  this
       variable  is  not set, or is null, and the [1m−e [22moption has not
       been selected, then [1m/bin/ed [22mis used.  When editing has  been
       complete,  the  edited  text automatically becomes the input
       for [1mksh[22m.  As this text is read by [1mksh[22m, it is echoed onto the
       terminal.

       The [1m−s [22moption causes the editing to be bypassed and just re‐
       executes the command.  In this case only  a  single  command
       can  be  specified  as the range and an optional argument of
       the form [4mold[24m[1m=[4m[22mnew[24m may be added which requests a simple string
       substitution prior to evaluation.  A convenient alias,
                            [1malias r=’hist ‐s’[0m
       has  been pre‐defined so that the single key‐stroke [1mr [22mcan be
       used to re‐execute the previous command and  the  key‐stroke
       sequence,  [1mr abc=def c  [22mcan  be  used to re‐execute the last
       command that  starts  with  the  letter  [1mc  [22mwith  the  first
       occurrence  of  the string [1mabc [22mreplaced with the string [1mdef[22m.
       Typing  [1mr c > file  [22mre‐executes  the  most  recent   command
       starting  with the letter [1mc[22m, with standard output redirected
       to [4mfile[24m.

       [4m2.4[24m  [4mIn‐line[24m [4mediting[0m

       Lines typed from a terminal  frequently  need  changes  made
       before entering them.  With the Bourne shell the only method
       to fix up commands is by backspacing or  killing  the  whole
       line.   [1mksh [22moffers options that allow the user to edit parts
       of the current command line before submitting  the  command.
       The in‐line edit options make the command line into a single
       line screen edit window.  When the command  is  longer  than
       the  width of the terminal, only a portion of the command is
       visible.  Moving within the line  automatically  makes  that
       portion  visible.   Editing  can be performed on this window
       until the [4mreturn[24m key is pressed.   The  editing  modes  have
       editing  directives  that  access  the history file in which
       previous commands are saved.  A user can  copy  any  of  the
       most  recent [1mHISTSIZE [22mcommands from this file into the input
       edit window.  You can locate commands  by  searching  or  by
       position.

       The  in‐line  editing  options  do  not  use  the [4mtermcap[24m or
       [4mterminfo[24m databases.  They work on most  standard  terminals.
       They  only  require  that  the backspace character moves the
       cursor left and the space character overwrites  the  current
       character  on  the screen and moves the cursor to the right.
       Very few terminals or terminal emulators do  not  have  this
       behavior.

       There  is  a choice of editor options.  The [1memacs[22m, [1mgmacs[22m, or
       [1mvi [22moption is selected by turning on the corresponding option
       of  the  [1mset  [22mcommand.  If the value of the [1mEDITOR [22mor [1mVISUAL[0m
       variables ends with any of these suffixes the  corresponding





       option  is  turned  on.   A  large  subset  of each of these
       editors’ features is available within the shell.  Additional
       functions,  such  as  file  name  completion, have also been
       added.

       In the [1memacs [22mor [1mgmacs [22mmode the user positions the cursor  to
       the  point  needing  correction  and  inserts,  deletes,  or
       replaces characters as needed.  The only difference  between
       these two modes is the meaning of the directive [1m^T[22m.  Control
       keys and escape sequences are used  for  cursor  positioning
       and  control functions.  The available editing functions are
       listed in the manual page.

       The [1mvi [22mediting mode starts in insert mode and enters control
       mode when the user types ESC ( 033 ).  The [4mreturn[24m key, which
       submits the current command for processing, can  be  entered
       from  either  mode.  The cursor can be anywhere on the line.
       A  subset  of  commonly  used  [4mvi[24m  editing  directives   are
       available.  The [1mk [22mand [1mj [22mdirectives that normally move up and
       down by one [4mline[24m, move  up  and  down  one  [4mcommand[24m  in  the
       history  file,  copying  the  command  into  the  input edit
       window.  For reasons of efficiency, the terminal is kept  in
       canonical  mode  until  an ESC is typed.  On some terminals,
       and on earlier versions of the UNIX operating  system,  this
       doesn’t work correctly.  The [1mviraw [22moption, which always uses
       [4mraw[24m or [4mcbreak[24m mode, must be used in this case.

       Most of the code for the editing options does  not  rely  on
       the [1mksh [22mcode and can be used in a stand‐alone mode with most
       any command to add in‐line edit  capability.   However,  all
       versions  of the in‐line editors have some features that use
       some shell specific code.  For example, with all edit modes,
       the ESC‐= directive applied to command words (the first word
       on the line, or the first word after a [1m;[22m, [1m|[22m, [1m([22m, or [1m&[22m)  lists
       all  aliases,  functions, or commands that match the portion
       of the given current word.  When  applied  to  other  words,
       this  directive  prints  the  names  of files that match the
       current word.  The ESC[1m‐* [22mdirective adds the expanded list of
       matching  files  to the command line.  A trailing [1m* [22mis added
       to the word if it doesn’t contain any file pattern  matching
       characters  before  the expansion.  In [1memacs [22mand [1mgmacs [22mmode,
       ESC‐ESC indicates command completion when applied to command
       names,  otherwise  it  indicates  pathname completion.  With
       command or pathname completion, the list  generated  by  the
       ESC‐=  directive  is  examined  to  find  the longest common
       prefix.  With command completion, only the last component of
       the  pathname is used to compute the longest command prefix.
       If the longest common prefix is a complete match,  then  the
       word  is  replaced  by  the pathname, and a [1m/ [22mis appended if
       pathname is a directory, otherwise a space is added.  In  [1mvi[0m
       mode, [1m\ [22mfrom control mode gives the same behavior.

       [4m2.5[24m  [4mKey[24m [4mBinding[0m

       It  is  possible  to  intercept keys as they are entered and
       apply new meanings or  bindings.   A  trap  named  [1mKEYBD  [22mis
       evaluated  each  time  [1mksh [22mprocesses characters entered from
       the keyboard, other than those typed while entering a search
       string  or an argument to an edit directive such as [1mr [22min vi‐
       mode.  The action associated with this trap can  change  the
       value  of  the  entered  key  to  cause the key to perform a





       different operation.

       When the [1mKEYBD [22mtrap  is  entered,  the  [1m.sh.edtext  [22mvariable
       contains  the  contents  of  the  current input line and the
       [1m.sh.edcol [22mvariable gives the current cursor position  within
       this   line.   The  [1m.sh.edmode  [22mvariable  contains  the  [1mESC[0m
       character when the trap is  entered  from  [1mvi  [22minsert  mode.
       Otherwise,  this  value  is  null.   The [1m.sh.edchar [22mvariable
       contains the character or escape sequence  that  caused  the
       trap.   A  key  sequence  is  either a single character, [1mESC[0m
       followed by a single character, or [1mESC[ [22mfollowed by a single
       character.   In  the  [1mvi [22medit mode, the characters after the
       [1mESC [22mmust be entered within half a second after the [1mESC[22m.  The
       value  of  [1m.sh.edchar [22mat the end of the trap will be used as
       the input sequence.

       Using the associative array facility of [1mksh [22mdescribed later,
       and  the  function  facility  of  [1mksh[22m, it is easy to write a
       single trap so that keys  can  be  bound  dynamically.   For
       example,

            [1mtypeset ‐A Keytable[0m
            [1mtrap ’eval "${Keytable[${.sh.edchar}]}"’ KEYBD[0m
            [1mfunction keybind # key action[0m
            [1m{[0m
                    [1mtypeset key=$(print ‐f "%q" "$2")[0m
                    [1mcase $# in[0m
                    [1m2)      Keytable[$1]=’.sh.edchar=${.sh.edmode}’"$key"[0m
                            [1m;;[0m
                    [1m1)      unset Keytable[$1][0m
                            [1m;;[0m
                    [1m*)      print ‐u2 "Usage: $0 key [action]"[0m
                            [1m;;[0m
                    [1mesac[0m
            [1m}[0m


       [4m2.6[24m  [4mJob[24m [4mControl[0m

       The job control mechanism is almost identical to the version
       introduced in [1mcsh [22mof the  Berkeley  UNIX  operating  system,
       version  4.1  and later.  The job control feature allows the
       user to stop and restart programs, and to move  programs  to
       and  from  the  foreground and the background.  It will only
       work on systems that provide  support  for  these  features.
       However,  even  systems  without  job control have a [1mmonitor[0m
       option which, when enabled,  will  report  the  progress  of
       background  jobs  and  enable  the  user to [1mkill [22mjobs by job
       number or job name.

       An interactive shell associates a  [4mjob[24m  with  each  pipeline
       typed  in  from  the terminal and assigns it a small integer
       number  called  the  job  number.   If  the   job   is   run
       asynchronously,  the  job number is printed at the terminal.
       At any given time, only one job  owns  the  terminal,  i.e.,
       keyboard  signals are only sent to the processes in one job.
       When [1mksh [22mcreates a foreground job, it gives it ownership  of
       the  terminal.  If you are running a job and wish to stop it
       you hit the key [1m^Z [22m(control‐[1mZ[22m) which sends a [1mSTOP [22msignal  to
       all  processes  in  the  current  job.   The  shell receives
       notification that the processes have stopped and takes  back





       control of the terminal.

       There  are  commands  to continue programs in the foreground
       and background.  There are several ways to  refer  to  jobs.
       The  character  [1m%  [22mintroduces  a job name.  You can refer to
       jobs by name or number as described in the manual page.  The
       built‐in  command  [1mbg  [22mallows  you  to continue a job in the
       background, while the built‐in  command  [1mfg  [22mallows  you  to
       continue  a  job  in the foreground even though you may have
       started it in the background.

       A job being run in the background will stop if it  tries  to
       read  from  the  terminal.   It  is  also  possible  to stop
       background jobs that try to write on the terminal by setting
       the terminal options appropriately.

       There  is  a  built‐in command [1mjobs [22mthat lists the status of
       all running and stopped jobs.  In addition, you are informed
       of   the  change  of  state  (running  or  stopped)  of  any
       background jobs just before each prompt.  If you want to  be
       notified  about  background  job completions as soon as they
       occur without waiting for a  prompt,  then  use  the  [1mnotify[0m
       option.   When  you  try  to  exit  the shell while jobs are
       stopped or running, you will receive a message from [1mksh[22m.  If
       you  ignore  this message and try to exit again, all stopped
       processes  will  be  terminated.   In  addition,  for  login
       shells,  the  [1mHUP [22msignal will be sent to all background jobs
       unless the job has been disowned with the [1mdisown [22mcommand.

       A built‐in version of [1mkill [22mmakes  it  possible  to  use  [4mjob[0m
       numbers  as targets for signals.  Signals can be selected by
       number or name.  The name of the signal is the name found in
       the  [4minclude[24m  file [1m/usr/include/sys/signal.h [22mwith the prefix
       [1mSIG [22mremoved.  The [1m−l [22moption of [1mkill [22mprovides a means to  map
       individual  signal  names  to  and  from  signal number.  In
       addition, if no signal name  or  number  is  given,  [1mkill ‐l[0m
       generates a list of valid signal names.

       [4m2.7[24m  [4mChanging[24m [4mDirectories[0m

       By  default, [1mksh [22mmaintains a logical view of the file system
       hierarchy  which  makes  symbolic  links  transparent.   For
       systems that have symbolic links, this means that if [1m/bin [22mis
       a symbolic link to [1m/usr/bin  [22mand  you  change  directory  to
       [1m/bin[22m,  [1mpwd [22mwill indicate that you are in [1m/bin[22m, not [1m/usr/bin[22m.
       [1mpwd ‐P  [22mgenerates  the  physical  pathname  of  the  present
       working  directory  by resolving all the symbolic links.  By
       default, the [1mcd [22mcommand will take you where you expect to go
       even if you cross symbolic links.  A subsequent [1mcd .. [22min the
       example above will place you in [1m/[22m,  not  [1m/usr[22m.   On  systems
       with   symbolic  links,  [1mcd ‐P  [22mcauses  [1m..   [22mto  be  treated
       physically.

       [1mksh [22mremembers your last directory in  the  variable  [1mOLDPWD[22m.
       The  [1mcd  [22mbuilt‐in  can be given with argument [1m− [22mto return to
       the previous directory and print the name of the  directory.
       Note  that  [1mcd ‐  [22mdone  twice  returns  you  to the starting
       directory, not the second previous directory.   A  directory
       [4mstack[24m  manager  has  been written as shell [4mfunctions[24m to [4mpush[0m
       and [4mpop[24m directories from the stack.







       [4m2.8[24m  [4mPrompts[0m

       When [1mksh [22mreads commands from a terminal, it issues a  prompt
       whenever it is ready to accept more input and then waits for
       the user to respond.  The [1mTMOUT [22mvariable can be  set  to  be
       the  number  of  seconds  that the shell will wait for input
       before terminating.  A 60 second warning message is  printed
       before terminating.

       The  shell uses two prompts.  The primary prompt, defined by
       the value of the [1mPS1 [22mvariable, is issued  at  the  start  of
       each command.  The secondary prompt, defined by the value of
       the [1mPS2 [22mvariable, is issued when more  input  is  needed  to
       complete a command.

       [1mksh   [22mallows  the  user  to  specify  a  list  of  files  or
       directories to check before issuing  the  [1mPS1  [22mprompt.   The
       variable  [1mMAILPATH  [22mis  a colon ( [1m: [22m) separated list of file
       names to be checked for changes periodically.  The  user  is
       notified  before the next prompt.  Each of the names in this
       list can be followed by a [1m?  [22mand a message to be given  when
       a  change has been detected in the file.  The prompt will be
       evaluated for parameter expansion, command substitution  and
       arithmetic   expansion   which  are  described  later.   The
       parameter [1m$_ [22mwithin a mail message will evaluate to the name
       of  the  file  that has changed.  The parameter [1mMAILCHECK [22mis
       used to specify the minimal interval in seconds  before  new
       mail is checked for.

       In  addition  to  replacing  each  [1m!  [22min the prompt with the
       command number, [1mksh [22mexpands the value of  the  [1mPS1  [22mvariable
       for parameter expansions, arithmetic expansions, and command
       substitutions as described below  to  generate  the  prompt.
       The  expansion  characters  that  are to be applied when the
       prompt is issued must be quoted to  prevent  the  expansions
       from  occurring  when  assigning  the  value  to  [1mPS1.   [22mFor
       example, [1mPS1="$PWD" [22mcauses [1mPS1 [22mto be set to the value of [1mPWD[0m
       at  the time of the assignment whereas [1mPS1=’$PWD’ [22mcauses [1mPWD[0m
       to be expanded at the time the prompt is issued.

       Command substitution  may  require  a  separate  process  to
       execute  and  cause  the prompt display to be somewhat slow,
       especially when the return key is pressed several times in a
       row.   Therefore,  its  use within [1mPS1 [22mis discouraged.  Some
       variables are maintained by [1mksh [22mso that their values can  be
       used  with [1mPS1.  [22mThe [1mPWD [22mvariable stores the pathname of the
       current working directory.  The value of [1mSECONDS [22mvariable is
       the  value  of  the  most recent assignment plus the elapsed
       time.  By default, the time is  measured  in  milli‐seconds,
       but  since  [1mSECONDS [22mis a floating point variable, the number
       of places after the decimal point in the expanded value  can
       be specified with [1mtypeset ‐F[4m[22mplaces[24m [1mSECONDS[22m.  In a roundabout
       way, this variable can be used to generate a time stamp into
       the  [1mPS1  [22mprompt  without creating a process at each prompt.
       The following code explains how you can do this on System V.
       On  BSD,  you  need  a  different  command to initialize the
       [1mSECONDS [22mvariable.

            [1m# . this script and use $TIME as part of your PS1 string to[0m
            [1m# get the time of day in your prompt[0m





            [1mtypeset ‐RZ2  _x1 _x2 _x3[0m
            [1m(( SECONDS=$(date  ’+3600*%H+60*%M+%S’) ))[0m
            [1m_s=’_x1=(SECONDS/3600)%24,_x2=(SECONDS/60)%60,_x3=SECONDS%60,0’[0m
            [1mTIME=’"${_d[_s]}$_x1:$_x2:$_x3"’[0m
            [1m# PS1=${TIME}whatever[0m



       [4m2.9[24m  [4mTilde[24m [4msubstitution[0m

       The character [1m∼ [22mat the  beginning  of  a  word  has  special
       meaning  to  [1mksh[22m.   If  the characters after the [1m∼ [22mup to a [1m/[0m
       match a user login name in the password database, then the [1m∼[0m
       and  the  name  are replaced by that user’s login directory.
       If no match is found, the original word is unchanged.   A  [1m∼[0m
       by  itself,  or in front of a [1m/[22m, is replaced by the value of
       the [1mHOME [22mparameter.  A [1m∼ [22mfollowed by a [1m+ [22mor [1m− [22mis replaced by
       the value of [1m$PWD [22mor [1m$OLDPWD [22mrespectively.

       [4m2.10[24m  [4mOutput[24m [4mformats[0m

       The  output  of  built‐in  commands  and  traces have values
       quoted so that they can be  re‐input  to  the  shell.   This
       makes it easy to cut and paste shell output on systems which
       use a pointing device such as a mouse.  In addition,  output
       can be saved in a file for reuse.

       [4m2.11[24m  [4mThe[24m [1mENV [4m[22mfile[0m

       When  an  interactive  [1mksh  [22mstarts,  it  evaluates  the [1m$ENV[0m
       variable to arrive at a file name.  If  this  value  is  not
       null, [1mksh [22mattempts to read and process commands in a file by
       this name.  Earlier versions of [1mksh [22mread the  [1mENV  [22mfile  for
       all  invocations  of  the  shell primarily to allow function
       definitions to be available for all shell invocations.   The
       function search path, [1mFPATH[22m, described later, eliminated the
       primary need for this capability and it was removed  because
       the high performance cost was no longer deemed acceptable.


       [4m3.[24m  [4mPROGRAMMING[24m [4mLANGUAGE[0m

       The  KornShell  vastly  extends the set of applications that
       can be implemented efficiently at the shell level.  It  does
       this  by providing simple yet powerful mechanisms to perform
       arithmetic,  pattern  matching,  substring  generation,  and
       arrays.   Users can write applications as separate functions
       that can be defined in the same file  or  in  a  library  of
       functions stored in a directory and loaded on demand.

       [4m3.1[24m  [4mString[24m [4mProcessing[0m

       The  shell  is  primarily  a string processing language.  By
       default, variables hold variable length strings.  There  are
       no  limits  to the length of strings.  Storage management is
       handled by the shell automatically.   Declarations  are  not
       required.  With most programming languages, string constants
       are designated by enclosing characters in single  quotes  or
       double  quotes.  Since most of the words in the language are
       strings, the  shell  requires  quotes  only  when  a  string
       contains characters that are normally processed specially by





       the shell, but their literal meaning is intended.   However,
       since  the  shell  is a string processing language, and some
       characters  can  occur   as   literals   and   as   language
       metacharacters,   quoting   is  an  important  part  of  the
       language.

       There are four quoting mechanisms in [1mksh[22m.  The  simplest  is
       to  enclose  a  sequence of characters inside single quotes.
       All characters between a pair of single  quotes  have  their
       literal meaning; the single quote itself cannot appear.  A [1m$[0m
       immediately preceding a single quoted string causes all  the
       characters until the matching single quote to be interpreted
       as  an  ANSI‐C  language  string.   Thus,  [1m’\n’   [22mrepresents
       characters  [1m\  [22mand [1mn[22m, whereas, [1m$’\n’ [22mrepresents the new‐line
       character.  Double quoted strings remove the special meaning
       of  all  characters  except  [1m$[22m,  [1m`[22m, and [1m\[22m, so that parameter
       expansion  and  command  substitution  (defined  below)  are
       performed.   The  final mechanism for quoting a character is
       by preceding it with the escape character [1m\[22m.  This mechanism
       works outside of quoted strings and for the characters [1m$[22m, [1m`[22m,
       [1m"[22m, and [1m\ [22min double quoted strings.

       Variables  are  designated  by  one  or  more   strings   of
       alphanumeric   characters   beginning   with  an  alphabetic
       character separated by a [1m.[22m.  Upper and lower case characters
       are  distinct,  so  that  the  variable [1mA [22mand [1ma [22mare names of
       different variables.  There is no limit to the length of the
       name  of  a variable.  You do not have to declare variables.
       You can assign a value to a variable by writing the name  of
       the  variable,  followed  by  an  equal  sign, followed by a
       character string that represents its  value.   To  create  a
       variable  whose  name  contains a [1m.[22m, the variable whose name
       consists of the characters before the last [1m.   [22mmust  already
       exist.   You reference a variable by putting the name inside
       curly braces and preceding the braces with  a  dollar  sign.
       The braces may be omitted when the name is alphanumeric.  If
       [1mx [22mand [1my [22mare two  shell  variables,  then  to  define  a  new
       variable,  [1mz[22m, whose value is the concatenation of the values
       of [1mx [22mand [1my[22m, you just say [1mz=$x$y[22m.  It is that easy.

       The [1m$ [22mcan be thought of as meaning "value of."  You can also
       capture   the  output  of  any  command  with  the  notation
       [1m$([4m[22mcommand[24m[1m)[4m[22m.[24m  This is referred to  as  command  substitution.
       For  example,  [1mx=$(date)  [22massigns  the  output from the [1mdate[0m
       command to the variable  [1mx[22m.   Command  substitution  in  the
       Bourne  shell  is  denoted  by enclosing the command between
       backquotes,  ([1m``[22m).   This   notation   suffers   from   some
       complicated  quoting  rules.   Thus, it is hard to write [1msed[0m
       patterns  which  contains  back   slashes   within   command
       substitution.   Putting  the  pattern in single quotes is of
       little  help.   [1mksh  [22maccepts  the   Bourne   shell   command
       substitution   syntax   for   backward  compatibility.   The
       [1m$([4m[22mcommand[24m[1m) [22mnotation allows the  [4mcommand[24m  itself  to  contain
       quoted strings even if the substitution occurs within double
       quotes. Nesting is legal.

       The special command substitution of the form [1m$(cat file) [22mcan
       be  replaced  by  [1m$(< file)[22m, which is faster because the [1mcat[0m
       command doesn’t have to run.







       [4m3.2[24m  [4mShell[24m [4mParameters[24m [4mand[24m [4mVariables[0m

       There are three types of parameters  used  by  [1mksh[22m,  special
       parameters,  positional  parameters,  and  named  parameters
       which are called variables.  [1mksh [22mdefines  the  same  special
       parameters,  [1m0[22m,  [1m*[22m,  [1m@[22m,  [1m#[22m, [1m?[22m, [1m$[22m, [1m![22m, and [1m−[22m, as in the Bourne
       shell.

       Positional parameters are set when the shell is invoked,  as
       arguments  to  the  [1mset  [22mbuilt‐in, and by calls to functions
       (see below) and [1m.  [22mprocedures.  They are  named  by  numbers
       starting at 1.

       The  third  type  of  parameter is a variable.  As mentioned
       earlier, [1mksh [22muses variables whose names consist  of  one  or
       more  alpha‐numeric  strings  separated by a [1m.[22m.  There is no
       need to specify the [4mtype[24m of a variable in the shell because,
       by  default, variables store strings of arbitrary length and
       values will automatically be converted to numbers when  used
       in  an  arithmetic context.  However, [1mksh [22mvariables can have
       one  or  more   [4mattributes[24m   that   control   the   internal
       representation  of  the  variable,  the  way the variable is
       printed, and its access or scope.  In addition,  [1mksh  [22mallows
       variables  to  represent  arrays of values and references to
       other  variables.   The  [1mtypeset  [22mbuilt‐in  command  of  [1mksh[0m
       assigns  attributes  to  variables.   Two of the attributes,
       [4mreadonly[24m and [4mexport[24m, are  available  in  the  Bourne  shell.
       Most  of  the  remaining attributes are discussed here.  The
       complete list of attributes  appears  in  the  manual.   The
       [1munset  [22mbuilt‐in  of  [1mksh  [22mremoves  values  and attributes of
       variables.  When a variable  is  exported,  certain  of  its
       attributes are also exported.

       Whenever  a  value  is  assigned to a variable, the value is
       transformed according to the  attributes  of  the  variable.
       Changing  the  attribute of a variable can change its value.
       The attributes [1m−L [22mand  [1m−R  [22mare  for  left  and  right  field
       justification  respectively.   They  are useful for aligning
       columns in a report.  For each of these attributes, a  width
       can  be  defined  explicitly or else it is defined the first
       time an assignment is made to the variable.  Each assignment
       causes  justification of the field, truncating if necessary.
       Assignment to fixed sized  variables  provides  one  way  to
       generate  a  substring  consisting  of  a  fixed  number  of
       characters from the beginning or end  of  a  string.   Other
       methods are discussed later.

       The  attributes  [1m−u [22mand [1m−l [22mare used for upper case and lower
       case formatting, respectively.  Since it makes no  sense  to
       have both attributes on simultaneously, turning on either of
       these attributes turns the other off.  The following script,
       using  [1mread [22mand [1mprint [22mwhich are described later, provides an
       example of the use of shell variables with attributes.  This
       script  reads a file of lines each consisting of five fields
       separated by [1m: [22mand prints fields 4 and 2 in  upper  case  in
       columns  1‐15,  left  justified,  and  columns  20‐25 right‐
       justified respectively.

            [1mtypeset ‐uL15 f4                # 15 character left justified[0m
            [1mtypeset ‐uR6 f2                 # 6 character right justified[0m
            [1mIFS=:                           # set field separator to :[0m





            [1mwhile   read ‐r f1 f2 f3 f4 f5  # read line, split into fields[0m
            [1mdo      print ‐r ‐‐ "$f4  $f2"  # print fields 4 and 2[0m
            [1mdone[0m


       The [1m−i[22m,  [1m−E[22m,  and  [1m−F[22m,  attributes  are  used  to  represent
       numbers.   Each can be followed by a decimal number.  The [1m−i[0m
       attribute causes the value to be represented as  an  integer
       and  it can be followed by a number representing the numeric
       base when expanding its value.  Whenever a value is assigned
       to  an  integer  variable,  it is evaluated as an arithmetic
       expression and then truncated to an integer.

       The [1m−E [22mattribute causes  the  value  to  be  represented  in
       scientific  notation  whenever  its  value is expanded.  The
       number following the [1m−E [22mdetermines the number of significant
       figures,  and  defaults  to  6.  The [1m−F [22mattribute causes the
       value to be represented with a fixed number of places  after
       the  decimal point.  Assignments to variables with the [1m−E [22mor
       [1m−F [22mattributes cause the evaluation of the right hand side of
       the assignment.

       [1mksh  [22mallows  one‐dimensional  [4marrays[24m  in  addition to simple
       variables.  There  are  two  types  of  arrays;  associative
       arrays and indexed arrays.  The subscript for an associative
       array is an arbitrary string, whereas the subscript  for  an
       indexed  array is an arithmetic expression that is evaluated
       to yield an integer  index.   Any  variable  can  become  an
       indexed  array by referring to it with an integer [4msubscript[24m.
       All elements of an array need  not  exist.   Subscripts  for
       arrays  must  evaluate  to  an  integer  between  0 and some
       maximum value, otherwise  an  error  results.   The  maximum
       value  may  vary from one machine to another but is at least
       4095.  Evaluation of subscripts is  described  in  the  next
       section.  Attributes apply to the whole array.

       Assignments  to  array  variables  can be made to individual
       elements via parameter assignment commands  or  the  [1mtypeset[0m
       built‐in.  Additionally, values can be assigned sequentially
       with compound assignment as described below, or  by  the  [1m−A[0m
       [4mname[24m  option of the [1mset [22mcommand.  Referencing of subscripted
       variables requires the character [1m$[22m, but also requires braces
       around  the  array  element  name.  The braces are needed to
       avoid conflicts with the  file  name  generation  mechanism.
       The form of any array element reference is:
                            [1m${[4m[22mname[24m[1m[[4m[22msubscript[24m[1m]}[0m
       Subscript  values  of  [1m*  [22mand  [1m@ [22mcan be used to generate all
       elements of an array, as they  are  used  for  expansion  of
       positional   parameters.   The  list  of  currently  defined
       subscripts for  a  given  variable  can  be  generated  with
       [1m${![4m[22mname[24m[1m[@]}[4m[22m,[24m or [1m${![4m[22mname[24m[1m[*]}[4m[22m.[0m

       The  [1m−n  [22mor  [4mnameref[24m  attribute  causes  the  variable to be
       treated as a reference to the variable defined by its value.
       Once  this attribute is set, all references to this variable
       become references to the variable named by the value of this
       variable.    For  example,  if  [1mfoo=bar[22m,  then  setting  the
       reference  attribute  on  [1mfoo  [22mwill  cause  all   subsequent
       references  to  [1mfoo  [22mto behave as the variable whose name is
       [1m$foo [22mwas referenced, which in this case is the variable [1mbar[22m.
       Unsetting  this attribute breaks the association.  Reference





       variables are usually used inside functions whose  arguments
       are  the  names of shell variables.  The names for reference
       variables cannot contain a [1m.[22m.  Whenever a shell variable  is
       referenced,  the  portion  of the variable up to the first [1m.[0m
       is checked to see whether it matches the name of a reference
       variable.   If  it  does,  then  the  name  of  the variable
       actually used consists of the concatenation of the  name  of
       the  variable  defined  by  the reference plus the remaining
       portion of the original variable name.  For  example,  using
       the predefined alias, [1malias nameref=’typeset ‐n’[22m,

            [1m.bar.home.bam="hello world"[0m
            [1mnameref foo=.bar.home[0m
            [1mprint ${foo.bam}[0m
            [1mhello world[0m


       [4m3.3[24m  [4mCompound[24m [4mAssignment[0m

       Compound assignments are used to assign values to arrays and
       compound  data  structures.   The  syntax  for  a   compound
       assignment  is [4mname[24m[1m=([4m[22massignment‐list[24m[1m) [22mwhere [4mname[24m is the name
       of the variable to which you  want  to  assign  values.   No
       space  is  permitted between the variable name and the [1m= [22mbut
       can appear between the [1m= [22mand  the  open  parenthesis.   New‐
       lines can appear between the parentheses.

       The  [4massignment‐list[24m  can  be  in  several  different  forms
       yielding different results.  If [4massignment‐list[24m is simply  a
       list of words, then the words are processed as they are with
       the [1mfor [22mcommand and  assigned  sequentially  as  an  indexed
       array.  For example,
                                [1mfoo=( * )[0m
       creates  an  indexed array [1mfoo [22mand assigns the file names in
       the current directory to each index starting at zero.

       The second form for [4massignment‐list[24m is a list of assignments
       of  the  special  form  [1m[[4m[22mword[24m[1m]=[4m[22mword[24m.   No space is permitted
       before or after the [1m=[22m.  In this case, the variable given  by
       [4mname[24m  becomes  an associative array with the given arguments
       as subscripts.  For example,
                     [1mbar=( [color]=red [shape]=box )[0m
       creates an associate array named [1mbar  [22mwhose  subscripts  are
       [1mcolor [22mand [1mshape[22m.

       The  third  form  for  [4massignment‐list[24m  is  a list of normal
       assignments,   including   compound   assignments.     These
       assignments cause sub‐variables to be assigned corresponding
       to the given assignments.  In addition to  assignments,  the
       [4massignment‐list[24m  can  contain [1mtypeset [22mcommands.  In addition
       to  creating  sub‐variables,  the  effect  of   a   compound
       assignment  is to make the value of the original variable be
       a parenthesized assignment  list  of  its  components.   For
       example, the assignment

            [1mfoo=([0m
                    [1mleft=bar[0m
                    [1mtypeset ‐i count=3[0m
                    [1mpoint=([0m
                            [1mx=50[0m
                            [1my=60[0m





                    [1m)[0m
                    [1mcolors=( red green yellow )[0m
                    [1mright=bam[0m
            [1m)[0m

       is equivalent to the assignments

            [1mfoo.left=bar[0m
            [1mfoo.count=3[0m
            [1mfoo.point.x=50[0m
            [1mfoo.point.y=60[0m
            [1mfoo.colors=( red green yellow )[0m
            [1mfoo.right=bam[0m

       In addition, the value of [1m"$foo" [22mis

            [1m([0m
                    [1mcolors=( red green yellow )[0m
                    [1mleft=bar[0m
                    [1mtypeset ‐i count=3[0m
                    [1mpoint=([0m
                            [1my=60[0m
                            [1mx=50[0m
                    [1m)[0m
                    [1mright=bam[0m
            [1m)[0m


       [4m3.4[24m  [4mSubstring[24m [4mGeneration[0m

       The  expansion of a variable or parameter can be modified so
       that only a portion of  the  value  results.   It  is  often
       necessary  to  extract  a  portion  of a shell variable or a
       portion of an array.  There are several parameter  expansion
       operators  that  can  do  this.   One  method  to generate a
       substring   is   with   an    expansion    of    the    form
       [1m${[4m[22mname[24m[1m:[4m[22moffset[24m[1m:[4m[22mlength[24m[1m}   [22mwhere   [4moffset[24m   is   an  arithmetic
       expression that defines the offset of  the  first  character
       starting from 0, and [4mlength[24m is an arithmetic expression that
       defines the length of the substring.  If [1m:[4m[22mlength[24m is omitted,
       the  length of the value of [4mname[24m starting at [4moffset[24m is used.
       The [1m:[4m[22moffset[24m[1m:[4m[22mlength[24m operators can also be  applied  to  array
       expansions and to parameters [1m* [22mand [1m@ [22mto generate portions of
       an     array.      For     example,      the      expansion,
       [1m${[4m[22mname[24m[1m[@]:[4m[22moffset[24m[1m:[4m[22mlength[24m[1m}[22m,  yields  up  to [4mlength[24m elements of
       the array [4mname[24m starting at the element [4moffset[24m.

       The other parameter expansion modifiers use  shell  patterns
       to  describe portions of the string to modify and delete.  A
       description of shell  patterns  is  contained  below.   When
       these modifiers are applied to special parameters [1m@ [22mand [1m* [22mor
       to  array  parameters  given  as  [4mname[24m[1m[@]  [22mor  [4mname[24m[1m[*][22m,  the
       operation  is  performed  on  each  element.  There are four
       parameter expansion modifiers that  strip  off  leading  and
       trailing  substrings  during parameter expansion by removing
       the characters matching a given pattern.   An  expansion  of
       the form [1m${[4m[22mname[24m[1m#[4m[22mpattern[24m[1m} [22mcauses the smallest matching prefix
       of the value of [4mname[24m to  be  removed.   The  largest  prefix
       matching  [4mpattern[24m  is  removed  by  using  [1m##  [22minstead of [1m#[22m.
       Similarly, an expansion of the form  [1m${[4m[22mname[24m[1m%[4m[22mpattern[24m[1m}  [22mcauses
       the  smallest  matching  substring  at the end of [4mname[24m to be





       removed.  Again, using [1m%% [22minstead of [1m%[22m, causes  the  largest
       matching  trailing substring to be deleted.  For example, if
       the shell variable [1mfile [22mhas value [1mfoo.c[22m, then the expression
       [1m${file%.c}.o [22mhas value [1mfoo.o[22m.

       The  value  of  an  expansion can be changed by specifying a
       pattern that matches the part that needs to be changed after
       the the parameter expansion modifier [1m/[22m.  An expansion of the
       form [1m${[4m[22mname[24m[1m/[4m[22mpattern[24m[1m/[4m[22mstring[24m[1m}  [22mreplaces  the  first  match  of
       [4mpattern[24m  with  the  value  of  variable [4mname[24m to [4mstring[24m.  The
       second  [1m/  [22mis  not  necessary  when  [4mstring[24m  is  null.   The
       expansion [1m${[4m[22mname[24m[1m//[4m[22mpattern[24m[1m/[4m[22mstring[24m[1m} [22mchanges all occurrences of
       the [4mpattern[24m into [4mstring[24m.  The parameter expansion  modifiers
       [1m/#  [22mand  [1m/% [22mcause the matching pattern to be anchored to the
       beginning and end respectively.

       Finally, there are parameter expansion modifiers that  yield
       the name of the variable, the string length of the value, or
       the number of elements of an  array.   [1m${![4m[22mname[24m[1m}  [22myields  the
       name  of  the variable which will be [4mname[24m itself except when
       [4mname[24m is a reference variable.  In this case  it  will  yield
       the  name  of the variable it refers to.  When applied to an
       array variable, [1m${![4m[22mname[24m[1m[@]}  [22mand  [1m${![4m[22mname[24m[1m[*]}  [22mgenerate  the
       names  of  all  subscripts.   [1m${#[4m[22mname[24m[1m} [22mwill be the length in
       bytes of [1m$[4m[22mname[24m.  For an array variable [1m${#[4m[22mname[24m[1m[*]} [22mgives the
       number of elements in the array.

       [4m3.5[24m  [4mArithmetic[24m [4mEvaluation[0m

       For  the  most  part,  the  shell  is  a  string  processing
       language.  However, the need for arithmetic  has  long  been
       obvious.   Many  of  the  characters that are special to the
       Bourne shell are needed as arithmetic  operators.   To  make
       arithmetic  easy  to use, and to maintain compatibility with
       the Bourne shell, [1mksh [22muses matching [1m(( [22mand [1m))  [22mto  delineate
       arithmetic expressions.  While single parentheses might have
       been more desirable, these already  mean  [4msubshell[24m  so  that
       another  notation  was  required.  The arithmetic expression
       inside the  double  parentheses  follows  the  same  syntax,
       associativity  and  precedence as the ANSI‐C[15] programming
       language.   The  characters  between  the  matching   double
       parentheses  are  processed  with  the  same  rules used for
       double quotes so that spaces can be used to aid  readability
       without additional quoting.

       All   arithmetic  evaluations  are  performed  using  double
       precision  floating  point   arithmetic.    Floating   point
       constants  follow  the  same rules as the ANSI‐C programming
       language.  Integer arithmetic constants are written as
                               [4mbase[24m[1m#[4m[22mnumber,[0m
       where [4mbase[24m is a decimal integer between two  and  sixty‐four
       and  [4mnumber[24m  is  any  non‐negative number.  Base ten is used
       when no base is specified.  The digits  are  represented  by
       the characters [1m0‐9a‐zA‐Z_@[22m.  For bases less than or equal to
       36,  upper  and  lower   case   characters   can   be   used
       interchangeably to represent the digits from 10 thru 35.

       Arithmetic  expressions  are made from constants, variables,
       and operators.  Parentheses may be used for  grouping.   The
       contents  inside  the  double parentheses are processed with
       the same expansions as occurs in a double quoted string,  so





       that all [1m$ [22mexpansions are performed before the expression is
       evaluated.  However, there is usually no need to use  the  [1m$[0m
       to  get  the  value  of  a  variable  because the arithmetic
       evaluator replaces the name of the  variable  by  its  value
       within  an arithmetic expression.  The [1m$ [22mcannot be used when
       the variable is the subject of assignment  or  an  increment
       operation.   As a rule it is better not to use [1m$ [22min front of
       variables in an arithmetic expression.

       An arithmetic command of the form [1m(( ...  ))  [22mis  a  command
       that  evaluates  the  enclosed  arithmetic  expression.  For
       example, the command
                                [1m(( x++ ))[0m
       can be used to increment the variable  [1mx[22m,  assuming  that  [1mx[0m
       contains  some  numerical  value.  The arithmetic command is
       true (return value 0), when the resulting expression is non‐
       zero,  and  false  (return  value  1)  when  the  expression
       evaluates to zero.  This makes the command easy to use  with
       the [1mif [22mand [1mwhile [22mcompound commands.

       The  [1mfor  [22mcompound  command  has  been  extended  for use in
       arithmetic contexts.  The syntax,
                      [1mfor (( [4m[22mexpr1[24m[1m; [4m[22mexpr2[24m [1m; [4m[22mexpr3[24m [1m))[0m
       can be used as the first line of a [1mfor [22mloop  with  the  same
       semantics  as  the  [1mfor  [22mstatement in the ANSI‐C programming
       language.

       Arithmetic evaluations can also be performed as part of  the
       evaluation of a command line.  The syntax [1m$(( ... )) [22mexpands
       to the value of the enclosed  arithmetic  expression.   This
       expansion   can   occur   wherever  parameter  expansion  is
       performed.   For  example  using  the  [1mksh   [22mcommand   [1mprint[0m
       (described later)
                              [1mprint $((2+2))[0m
       prints the number 4.

       The  following  script  prints  the  first  [4mn[24m  lines  of its
       standard input onto its standard  output,  where  [4mn[24m  can  be
       supplied as an optional argument whose default value is 20.

            [1minteger n=${1‐20}                       # set n[0m
            [1mwhile   (( n‐‐ >=0 )) && read ‐r line   # at most n lines[0m
            [1mdo      print ‐r ‐‐ "$line"[0m
            [1mdone[0m


       [4m3.6[24m  [4mShell[24m [4mExpansions[0m

       The  commands  you  enter from the terminal or from a script
       are divided into  words  and  each  word  undergoes  several
       expansions  to  generate the command name and its arguments.
       This is done in two  phases.   The  first  phase  recognizes
       reserved words, spaces and operators to decide where command
       boundaries lie.  Alias substitutions take place during  this
       phase.    The   second  phase  performs  expansions  in  the
       following order:

          · Tilde  substitution,  parameter  expansion,  arithmetic
            expansion,  and command substitution are performed from
            left to right.  The option [1m−u [22mor [1mnounset[22m, will cause an
            error  to  occur  when  any variable that is not set is





            expanded.

          · The characters that result from parameter expansion and
            command   substitution   above  are  checked  with  the
            characters in  the  [1mIFS  [22mvariable  for  possible  field
            splitting.  (See a description of [1mread [22mbelow to see how
            [1mIFS [22mis used.)  Setting [1mIFS [22mto a null value causes field
            splitting to be skipped.

          · Pathname  generation  (as described below) is performed
            on each of the fields.  Any field that doesn’t match  a
            pathname  is  left alone.  The option, [1m−f [22mor [1mnoglob[22m, is
            used to disable pathname generation.

       [4m3.7[24m  [4mPattern[24m [4mMatching[0m

       The shell is primarily a string processing language and uses
       patterns  for  matching  file  names as well as for matching
       strings.  The characters [1m?[22m, [1m*[22m, and [1m[ [22mare processed specially
       by  the shell when not quoted.  These characters are used to
       form patterns that match strings.  Patterns are used by  the
       shell  to  match  pathnames,  to specify substrings, and for
       [1mcase [22mcommands.  The character [1m?  [22mmatches any one  character.
       The  character  [1m*  [22mmatches  zero  or  more  characters.  The
       character sequence [1m[[22m...[1m]  [22mdefines  a  character  class  that
       matches  any  character  contained  within  [1m[][22m.   A range of
       characters can be specified by putting a [1m− [22mbetween the first
       and  last  character  of the range.  An exclamation mark, [1m![22m,
       immediately after the [1m[[22m, means match all  characters  except
       the   characters   specified.    For  example,  the  pattern
       [1ma?c*.[!a‐z] [22mmatches any string beginning with  an  [1ma[22m,  whose
       third  character  is a [1mc[22m, and that ends in [1m.  [22m(dot) followed
       by any character except the lower case  letters,  [1ma−z[22m.   The
       sequence [1m[:alpha:] [22minside a character class, matches any set
       of  characters  in  the  ANSI‐C  [1malpha  [22mclass.    Similarly,
       [1m[:[4m[22mclass[24m[1m:]  [22mmatches each of the characters in the given [4mclass[0m
       for  all  the  ANSI‐C  character  classes.    For   example,
       [1m[[:alnum:]_]  [22mmatches  any  alpha‐numeric  character  or the
       character [1m_[22m.

       [1mksh [22mtreats  strings  of  the  form  [1m([4m[22mpattern‐list[24m  [1m)[22m,  where
       [4mpattern‐list[24m  is a list of one or more patterns separated by
       a [1m⎪[22m, specially when preceded by [1m*[22m, [1m?[22m,  [1m+[22m,  [1m@[22m,  or  [1m![22m.   A  [1m?[0m
       preceding   [1m([4m[22mpattern‐list[24m[1m)   [22mmeans  that  the  pattern  list
       enclosed in [1m() [22mis optional.  An [1m@([4m[22mpattern‐list[24m[1m) [22mmatches  any
       pattern   in  the  list  of  patterns  enclosed  in  [1m()[22m.   A
       [1m*([4m[22mpattern‐list[24m[1m) [22mmatches any string  that  contains  zero  or
       more  of  each  of the enclosed patterns, whereas [1m+([4m[22mpattern‐[0m
       [4mlist[24m[1m) [22mrequires a match of one or more of any  of  the  given
       patterns.   For  instance, the pattern [1m+([0−9])?(.)  [22mmatches
       one or more digits  optionally  followed  by  a  [1m.[22m(dot).   A
       [1m!([4m[22mpattern‐list[24m[1m)  [22mmatches  anything  except  any of the given
       patterns.  For example, [1mprint !(*.o) [22mdisplays all file names
       in the current directory that do not end in [1m.o[22m.

       When  patterns are used to generate pathnames when expanding
       commands several other rules apply.   A  separate  match  is
       made  for  each  file  name component of the pathname.  Read
       permission is required for any portion of the pathname  that
       contains  any  special pattern character.  Search permission
       is required for every component except possibly the last.






       By default, file names in each directory that begin  with  [1m.[0m
       are  skipped  when performing a match.  If the pattern to be
       matched starts with a leading [1m.[22m, then only  files  beginning
       with  a  [1m.[22m, are examined when reading each directory to find
       matching files.  If the [1mFIGNORE [22mvariable is set,  then  only
       files  that  do not match this pattern are considered.  This
       overrides the special meaning of [1m.  [22min a pattern  and  in  a
       file name.

       If  the  [1mmarkdirs [22moption is set, each matching pathname that
       is the name of a directory has a trailing [1m/ [22mappended to  the
       name.

       [4m3.8[24m  [4mConditional[24m [4mExpressions[0m

       The  Bourne shell uses the [1mtest [22mcommand, or the equivalent [1m[[0m
       command, to test files for attributes and to compare strings
       or  numbers.   The  problem  with [1mtest [22mis that the shell has
       expanded the words of the [1mtest [22mcommand and split  them  into
       arguments   before   [1mtest  [22mbegins  execution.   [1mtest  [22mcannot
       distinguish between operators and operands.  In  most  cases
       [1mtest "$1"   [22mwill   test  whether  argument  1  is  non‐null.
       However, if argument 1 is [1m−f[22m, then [1mtest [22mwill treat [1m−f [22mas  an
       operator and yield a syntax error.  One of the most frequent
       errors with [1mtest [22moccurs when its  operands  are  not  within
       double  quotes.   In  this  case, the argument may expand to
       more than a single argument or to no argument  at  all.   In
       either  case  this  will  likely cause a syntax error.  What
       makes  this  most  insidious  is  that  these   errors   are
       frequently  data  dependent.   A  script that appears to run
       correctly may abort if given unexpected data.

       To get around these problems, [1mksh [22mhas a compound command for
       conditional expression testing as part of the language.  The
       reserved words [1m[[ [22mand [1m]] [22mdelimit the range of  the  command.
       Because  they  are  reserved words, not operator characters,
       they require spaces to separate them  from  arguments.   The
       words  between  [1m[[  [22mand  [1m]]  [22mare  not  processed  for  field
       splitting or for pathname generation.   In  addition,  since
       [1mksh  [22mdetermines  the  operators  before parameter expansion,
       expansions that yield no argument  cause  no  problem.   The
       operators  within  [1m[[[22m...[1m]]  [22mare almost the same as those for
       the [1mtest [22mcommand.  All  unary  operators  are  of  the  form
       [1m−[4m[22mletter[24m and are followed by a single operand.  Instead of [1m−a[0m
       and [1m−o[22m, [1m[[[22m...[1m]] [22muses [1m&& [22mand [1m⎪⎪ [22mto indicate "and"  and  "or".
       Parentheses are used without quoting for grouping.

       The  right  hand  side of the string comparison operators [1m==[0m
       and [1m!= [22mtakes a pattern  and  tests  whether  the  left  hand
       operand  matches  this pattern.  Quoting the pattern results
       is a string comparison rather than the pattern  match.   The
       operators  [1m<  [22mand [1m> [22mwithin [1m[[[22m...[1m]] [22mdesignate lexicographical
       comparison.

       In  addition  there  are  several   other   new   comparison
       primitives.   The  binary  operators [1m−ot [22mand [1m−nt [22mcompare the
       modification times of two files to see which file  is  [4molder[0m
       [4mthan[24m or [4mnewer[24m [4mthan[24m the other.  The binary operator [1m−ef [22mtests
       whether two files have the same device  and  i‐node  number,
       i. e., a link to the same file.






       The  unary  operator  [1m−L  [22mreturns  true  if its operand is a
       symbolic link.  The unary operator [1m−O [22m([1m−G[22m) returns  true  if
       the owner (or group) of the file operand matches that of the
       caller.  The unary operator [1m−o [22mreturns true when its operand
       is the name of an option that is currently on.

       The  following  script  illustrates  some  of  the  uses  of
       [1m[[[22m...[1m]][22m.  The reference manual contains the complete list of
       operators.

            [1mfor i[0m
            [1mdo      # execute foo for numeric directory[0m
                    [1mif      [[ −d $i && $i == +([0−9]) ]][0m
                    [1mthen    foo[0m
                    [1m# otherwise if writable or executable file and not mine[0m
                    [1melif    [[ (−w $i⎪⎪−x $i) && ! −O $i ]][0m
                    [1mthen    bar[0m
                    [1mfi[0m
            [1mdone[0m


       [4m3.9[24m  [4mInput[24m [4mand[24m [4mOutput[0m

       [1mksh  [22mhas extended I/O capabilities to enhance the use of the
       shell as a programming language.  As with the Bourne  shell,
       you  use  the  I/O redirection operator, [1m<[22m, to control where
       input comes from, and the I/O redirection  operator,  [1m>[22m,  to
       control  where  output goes to.  Each of these operators can
       be preceded with a single digit that specifies a  file  unit
       number  to  associate  with the file stream.  Ordinarily you
       specify these I/O  redirection  operators  with  a  specific
       command  to  which  it applies.  However, if you specify I/O
       redirections  with  the  [1mexec  [22mcommand,  and  don’t  specify
       arguments  to  [1mexec[22m, then the I/O redirection applies to the
       current program.  For  example,  the  command  [1mexec < foobar[0m
       opens  file  [1mfoobar  [22mfor  reading.  The [1mexec [22mcommand is also
       used to close files.  A file descriptor unit can  be  opened
       as  a  copy  of  an  existing  file descriptor unit by using
       either of the [1m<&  [22mor  [1m>&  [22moperators  and  putting  the  file
       descriptor  unit  of  the  original file after the [1m&[22m.  Thus,
       [1m2>&1 [22mmeans open standard error (file descriptor 2) as a copy
       of  standard  output (file descriptor 1).  A file descriptor
       value of [1m− [22mafter the [1m& [22mindicates that  the  file  should  be
       closed.  To close file unit 5, specify [1mexec 5<&‐[22m.  There are
       two additional redirection operators with [1mksh [22mand the  POSIX
       shell  that  are  not  part  of  the  Bourne  shell.  The [1m>|[0m
       operator  overrides  the  effect  of  the  [1mnoclobber  [22moption
       described  earlier.   The  [1m<>  [22moperator  causes a file to be
       opened for both reading and writing.

       [1mksh [22mrecognizes certain pathnames and treats them  specially.
       Pathnames of the form [1m/dev/fd/[4m[22mn[24m are treated as equivalent to
       the file defined by file descriptor [4mn[24m.  These  name  can  be
       used  as  the  script  argument  to  [1mksh  [22mand in conditional
       testing as described  above.   On  underlying  systems  that
       support  [1m/dev/fd  [22min  the  file  system,  these names can be
       passed  to  other   commands.    Pathnames   of   the   form
       [1m/dev/tcp/[4m[22mhostid[24m[1m/[4m[22mport[24m and [1m/dev/udp/[4m[22mhostid[24m[1m/[4m[22mport[24m can be used to
       create [1mtcp [22mand [1mudp [22mconnections  to  services  given  by  the
       [4mhostid[24m  number  and  [4mport[24m  number.   The  [4mhostid[24m  cannot use





       symbolic values. In practice  these  numbers  are  typically
       generated    by    command   substitution.    For   example,
       [1mexec 5> /dev/tcp/$(service name) [22mwould open file  descriptor
       5  for sending messages to hostid and port number defined by
       the output of [1mservice name[22m.

       The Bourne shell has a built‐in  command  [1mread  [22mfor  reading
       lines  from standard input (file descriptor 0) and splitting
       it into fields based on the value of the [1mIFS [22mvariable, and a
       command  [1mecho [22mto write strings to standard output.  (On some
       systems,  [1mecho  [22mis  not  a  built‐in  command   and   incurs
       considerable  overhead  to  use.)  Unfortunately, neither of
       these commands is able to perform  some  very  basic  tasks.
       For  example.   with  the  Bourne  shell,  the [1mread [22mbuilt‐in
       cannot read a single line that ends in [1m\[22m.  With [1mksh [22mthe [1mread[0m
       built‐in has a [1m−r [22moption to remove the special meaning for [1m\[0m
       which allows it to be treated as a regular character  rather
       than  the  line  continuation  character.   With  the Bourne
       shell, there is no simple way to have  more  than  one  file
       open  at  any time for reading.  [1mksh [22mhas options on the [1mread[0m
       command to specify the file descriptor for the  input.   The
       fields  that  are  read  from  a  line can be stored into an
       indexed array with the [1m−A [22moption to  read.   This  allows  a
       line to be split into an arbitrary number of fields.

       The  way  the  Bourne  shell  uses the [1mIFS [22mvariable to split
       lines into fields greatly limits its  utility.   Often  data
       files  consist  of  lines  that use a character such as [1m: [22mto
       delimit fields with two adjacent delimiters  that  denote  a
       null  field.  The Bourne shell treats adjacent delimiters as
       a single field delimiter.  With  [1mksh[22m,  delimiters  that  are
       considered  white  space characters have the behavior of the
       Bourne shell, but other adjacent  delimiters  separate  null
       fields.

       The [1mread [22mcommand is often used in scripts that interact with
       the user by prompting the  user  and  then  requesting  some
       input.   With  the Bourne shell two commands are needed; one
       to prompt the user, the other to read the reply.  [1mksh [22mallows
       these  two  commands  to be combined.  The first argument of
       the [1mread [22mcommand can be followed by a [1m?  [22mand a prompt string
       which  is  used  whenever  the  input  device is a terminal.
       Because the prompt is associated with the [1mread [22mbuilt‐in, the
       built‐in  command line editors will be able to re‐output the
       prompt whenever the line needs to be refreshed when  reading
       from a terminal device.

       With  the  Bourne shell, there is no way to set a time limit
       for waiting for the user response to read.  The [1m−t [22moption to
       [1mread  [22mtakes a floating point argument that gives the time in
       seconds, or fractions of seconds that the shell should  wait
       for a reply.

       The  version  of the [1mecho [22mcommand in System V treats certain
       sequences beginning with [1m\ [22mas control sequences.  This makes
       it  hard to output strings without interpretation.  Most BSD
       derived  systems  do  not  interpret  [1m\  [22mcontrol  sequences.
       Unfortunately,  the BSD versions of [1mecho [22maccepts a [1m−n [22moption
       to prevent a trailing new‐line, but has no way to cause  the
       string  [1m−n  [22mto  be  printed.   Neither  of these versions is
       adequate. Also, because they are incompatible,  it  is  very





       hard  to  write  portable shell scripts using [1mecho[22m.  The [1mksh[0m
       built‐in, [1mprint[22m, outputs characters to the terminal or to  a
       file  and  subsumes  the  functions of all versions of [1mecho[22m.
       Ordinarily, escape sequences in arguments beginning  with  [1m\[0m
       are  processed  the  same  as for the System V [1mecho [22mcommand.
       However [1mprint [22mfollows the standard conventions  for  options
       and  has  options  that  make  [1mprint [22mvery versatile.  The [1m−r[0m
       option can be used  to  output  the  arguments  without  any
       special meaning.  The [1m−n [22moption can be used here to suppress
       the trailing new‐line that is ordinarily appended.  As  with
       [1mread[22m,  it  is possible to specify the file descriptor number
       as  an  option  to  the  command  to  avoid  having  to  use
       redirection operators with each occurrence of the command.

       The  IEEE  POSIX  shell and utilities standard committee was
       unable to reconcile the differences between the System V and
       BSD  versions  of [1mecho[22m.  They introduced a new command named
       [1mprintf [22mwhich takes an ANSI‐C format string  and  a  list  of
       options  and outputs the strings using the ANSI‐C formatting
       rules.  Since [1mksh [22mis POSIX conforming,  it  accepts  [1mprintf[22m.
       However,  there is a [1m−f [22moptions to [1mprint [22mthat can be used to
       specify a format string which processes  the  arguments  the
       same way that [1mprintf [22mdoes.

       The format processing for [1mprint [22mand [1mprintf [22mhas been extended
       slightly.  There are three additional formatting directives.
       The  [1m%b  [22mformat causes the [1m\ [22mescape sequences to be expanded
       as they are with the System V [1mecho [22mcommand.  The  [1m%q  [22mformat
       causes quotes to be placed on the output as required so that
       it can be used as shell input.  Special  characters  in  the
       output  of most [1mksh [22mbuilt‐in commands and in the output from
       an execution trace are quoted in an equivalent fashion.  The
       [1m%P [22mformat causes an extended regular expression string to be
       converted into a shell pattern.  This is useful for  writing
       shell  applications  that have to accept regular expressions
       as input.  Finally, the escape sequence [1m\E [22mwhich expands  to
       the terminal escape character (octal 033) has been added.

       The  shell  is frequently used as a programming language for
       interactive dialogues.  The [1mselect [22mstatement has been  added
       to  the language to make it easier to present menu selection
       alternatives to the user and evaluate the reply.   The  list
       of  alternatives  is  numbered  and  put in columns.  A user
       settable prompt, [1mPS3[22m, is issued  and  if  the  answer  is  a
       number  corresponding to one of the alternatives, the select
       loop variable is set to this value.  In any case, the  [1mREPLY[0m
       variable is used to store the user entered reply.  The shell
       variables [1mLINES [22mand [1mCOLUMNS [22mare used to control  the  layout
       of select lists.

       [4m3.10[24m  [4mOption[24m [4mParsing[0m

       The  [1mgetopts [22mbuilt‐in command can be used to process command
       arguments in a manner consistent with the way [1mksh  [22mdoes  for
       its own built‐in commands.

       The  [1mgetopts  [22mbuilt‐in  allows  users  to specify options as
       separate arguments or to group  options  that  do  not  take
       arguments  together.   Options that require arguments do not
       require space to separate them  from  the  option  argument.
       The  [1mOPTARG [22mvariable stores the value of the option argument





       after finding a variable that takes an argument.  The [1mOPTIND[0m
       variable  holds  the  index of the current options argument.
       After processing options, the arguments should be shifted by
       [1mOPTIND−1 [22mto make the remaining arguments be [1m"$@"[22m.

       The   [1mgetopts   [22margument   description   allows   additional
       information to be specified along with the options  that  is
       used  to generate [4musage[24m messages for incorrect arguments and
       for the option argument [1m−?[22m.  The  example  in  the  APPENDIX
       uses [1mgetopts [22mto process its arguments.

       [4m3.11[24m  [4mCo‐process[0m

       [1mksh  [22mcan  spawn a [4mco‐process[24m by adding a [1m|& [22mafter a command.
       This process will be run with its  standard  input  and  its
       standard  output  connected  to  the  shell.   The  built‐in
       command [1mprint  [22mwith  the  [1m−p  [22moption  will  write  into  the
       standard input of this process and the built‐in command [1mread[0m
       with the [1m−p  [22moption  will  read  from  the  output  of  this
       process.

       In  addition, the I/O redirection operators [1m<& [22mand [1m>& [22mcan be
       used to move the input or output pipe of the co‐process to a
       numbered  file descriptor.  Use [1mexec 3>& p [22mto move the input
       of the co‐process to file  descriptor  [1m3[22m.   After  you  have
       connected to file descriptor [1m3[22m, you can direct the output of
       any command to the co‐process by running [4mcommand[24m [1m>&3[22m.  Also,
       by  moving  the  input  of  the  co‐process  to  a  numbered
       descriptor, it is possible to run a second co‐process.   The
       output  of  both  co‐processes  will  be the file descriptor
       associated with [1mread ‐p[22m.  You can use  [1mexec 4<& p  [22mto  cause
       the  output of these co‐processes to go to file descriptor [1m4[0m
       of the shell.  Once you have moved the pipe to descriptor [1m4[22m,
       it  is  possible  to  connect  a server to the co‐process by
       running [4mcommand[24m [1m4<& p [22mor to close the co‐process  pipe  with
       [1mexec 4<& ‐[22m.

       [4m3.12[24m  [4mFunctions[0m

       Function definitions are of the form

            [1mfunction [4m[22mname[0m
            [1m{[0m
                    any shell script
            [1m}[0m

       A  function  whose name contains a [1m.  [22mis called a [4mdiscipline[0m
       function.  The portion of the name after the last [1m.  [22mis  the
       name  of  the  discipline.   Discipline functions named [1mget[22m,
       [1mset[22m, and [1munset [22mcan be assigned to any variable to  intercept
       lookups,  assignments  and unsetting of the variable defined
       by the portion of the name before the last [1m.[22m.   Applications
       can  create  additional  disciplines  for variables that are
       created as part of user defined built‐ins.  The  portion  of
       the  name  before  the  last [1m.  [22mmust refer to the name of an
       existing variable.  Thus, if [1mp [22mis a reference to [1mPATH[22m,  then
       the  function  name  [1mp.get  [22mand  [1mPATH.get  [22mrefer to the same
       function.

       The function is invoked either by  specifying  [4mname[24m  as  the
       command  name  and optionally following it with arguments or





       by using it  as  an  option  to  the  [1m.   [22mbuilt‐in  command.
       Positional  parameters  are  saved before each function call
       and restored when completed.  The arguments that follow  the
       function   name   on  the  calling  line  become  positional
       parameters inside the function.  The [1mreturn [22mbuilt‐in can  be
       used  to  cause  the  function  to  return  to the statement
       following the point of invocation.

       Functions can also be defined with the System V notation,

            [4mname[24m [1m()[0m
            [1m{[0m
                    any shell script
            [1m}[0m

       Functions defined with this syntax cannot  be  used  as  the
       first  argument to a [1m. [22mprocedure.  [1mksh [22maccepts this notation
       for compatibility only.   There  is  no  need  to  use  this
       notation when writing [1mksh [22mscripts.

       Functions  defined with the [1mfunction [4m[22mname[24m syntax and invoked
       by name are executed in the current  shell  environment  and
       can   share   named  variables  with  the  calling  program.
       Options, other than execution trace [1m−x[22m, set by  the  calling
       program  are passed down to a function.  The options are not
       shared with the function so that any options  set  within  a
       function  are  restored  when  the  function  exits.   Traps
       ignored by the caller are ignored within  the  function  and
       cannot  be enabled.  Traps caught by the calling program are
       reset to their default action within the function.  In  most
       instances,  the  default  action is to cause the function to
       terminate.   A  trap  on  [1mEXIT  [22mdefined  within  a  function
       executes  after the function completes but before the caller
       resumes.   Therefore,  any  variable  assignments  and   any
       options set as part of a trap action will be effective after
       the caller resumes.

       By default, variables are  inherited  by  the  function  and
       shared  by  the  calling  program.   However,  for functions
       defined with the [1mfunction [4m[22mname[24m syntax that  are  invoked  by
       name,  environment substitutions preceding the function call
       apply only  to  the  scope  of  the  function  call.   Also,
       variables  whose  names do not contain a [1m.  [22mthat are defined
       with the [1mtypeset [22mbuilt‐in command are local to the  function
       that they are declared in.  Thus, for the function defined

            [1mfunction  name[0m
            [1m{[0m
                 [1mtypeset ‐i x=10[0m
                 [1mlet z=x+y[0m
                 [1mprint $z[0m
            [1m}[0m

       invoked  as  [1my=13 name[22m,  [1mx  [22mand  [1my  [22mare local variables with
       respect to the function [1mname [22mwhile [1mz [22mis global.

       Functions defined with  the  [4mname[24m[1m()  [22msyntax,  and  functions
       invoked  as  an argument to the [1m.  [22mcommand, share everything
       other  than   positional   parameters   with   the   caller.
       Assignments that precede the call remain in effect after the
       function completes.






       Alias and function  names  are  not  passed  down  to  shell
       scripts  or carried across separate invocations of [1mksh[22m.  The
       [1m$FPATH [22mvariable gives a colon separated list of  directories
       that  is  searched  for  function definitions when trying to
       resolve the command name.  Whenever a file name contained in
       [1m$FPATH [22mis found, the complete file is read and all functions
       contained within become defined.

       Calls that reference functions can be recursive.  Except for
       special  built‐ins,  function  names  take  precedence  over
       built‐in names and names of programs when  used  as  command
       names.   To  write  a  replacement function that invokes the
       command that you wish to replace, you can  use  the  [1mcommand[0m
       built‐in command.  The arguments to [1mcommand [22mare the name and
       arguments of the program you want to execute.   For  example
       to  write  a  [1mcd  [22mfunction  which  changes the directory and
       prints out the directory name, you can write

            [1mfunction  cd[0m
            [1m{[0m
                 [1mif      command cd  "$@"[0m
                 [1mthen    print  ‐r ‐‐ $PWD[0m
                 [1mfi[0m
            [1m}[0m


       The [1mFPATH [22mvariable is a colon separated list that  [1mksh  [22muses
       to  search for function definitions.  When [1mksh [22mencounters an
       autoload function, it runs the  [1m.   [22mcommand  on  the  script
       containing the function, and then executes the function.

       For  interactive  shells,  function  definitions may also be
       placed in the [1mENV [22mfile.  However, this causes the  shell  to
       take longer to begin executing.

       [4m3.13[24m  [4mProcess[24m [4mSubstitution[0m

       This  feature  is  only  available  on  versions of the UNIX
       operating system which support  the  [1m/dev/fd  [22mdirectory  for
       naming  open  files.   Each  command  argument  of  the form
       [1m<([4m[22mlist[24m[1m) [22mor [1m>([4m[22mlist[24m[1m)  [22mwill  run  process  [4mlist[24m  asynchronously
       connected  to  some file in the [1m/dev/fd [22mdirectory.  The name
       of this file will become the argument to  the  command.   If
       the  form  with [1m> [22mis selected then writing on this file will
       provide input for [4mlist[24m.  If [1m< [22mis used, then the file  passed
       as  an argument will contain the output of the [4mlist[24m process.
       For example,

            [1mpaste  <(cut −f1 [4m[22mfile1[24m[1m)  <(cut −f2 [4m[22mfile2[24m[1m) | tee >([4m[22mprocess1[24m[1m)  >([4m[22mprocess2[24m[1m)[0m

       extracts fields 1 and 3  from  the  files  [4mfile1[24m  and  [4mfile2[0m
       respectively,  places the results side by side, and sends it
       to the processes [4mprocess1[24m and [4mprocess2[24m, as well  as  putting
       it  onto  the  standard output.  Note that the file which is
       passed as an argument  to  the  command  is  a  UNIX  system
       [4mpipe[24m(2)  so that the programs that expect to [4mlseek[24m(2) on the
       file will not work.

       [4m3.14[24m  [4mFinding[24m [4mCommands[0m






       The addition of aliases, functions, and more  built‐ins  has
       made  it  substantially  more difficult to know what a given
       command name really means.

       Commands that begin with reserved words are an integral part
       of  the  shell  language  itself  and  typically  define the
       control flow of the language.  Some  control  flow  commands
       are  not  reserved  words  in  the  language but are [4mspecial[0m
       built‐ins.   Special  built‐ins  are  built‐ins   that   are
       considered a part of the language rather than user definable
       commands.  The best  examples  of  commands  that  fit  this
       description  are  [1mbreak  [22mand [1mcontinue[22m.  Because they are not
       reserved words, they can be the result of  shell  expansions
       and  are  not  effected by quoting.  These commands have the
       following special properties:

          · Assignments that precede  them  apply  to  the  current
            shell process, not just to the given command.

          · An  error in the format of these commands cause a shell
            script or function that contains them to abort.

          · They cannot be overridden by shell functions.

       Other  commands  are  built‐in  because  they  perform  side
       effects  on  the  current  environment  that would be nearly
       impossible to implement otherwise.  Built‐ins such as [1mcd [22mand
       [1mread  [22mare  examples  of such built‐ins.  These built‐ins are
       semantically equivalent to commands that  are  not  built‐in
       except that they don’t take a path search to locate.

       A third reason to have a command built‐in is so that it will
       be unaffected by the setting  of  the  [1mPATH  [22mvariable.   The
       [1mprint   [22mcommand  fits this category.  Scripts that use [1mprint[0m
       will be portable to all sites that run [1mksh[22m.

       The final reason for having a command be a built‐in  is  for
       performance.   On  most  systems it is more than an order of
       magnitude faster to initiate a command that is built‐in than
       to  create  a separate process to run the command.  Examples
       that fit this category are [1mtest [22mand [1mpwd[22m.

       Given a command name [1mksh [22mdecides what  it  means  using  the
       following order:

          · Reserved  words  define  commands that form part of the
            shell grammar.  They cannot be quoted.

          · Alias substitutions occur first as part of the  reading
            of  commands.   Using  quotes  in the command name will
            prevent alias substitutions.

          · Special built‐ins.

          · Functions.

          · Commands that are built‐in that are not associated with
            a pathname such as [1mcd [22mand [1mprint[22m.

          · If the command name contains a [1m/[22m, the program or script
            corresponding to the given name is executed.






          · A path search locates the pathname corresponding to the
            command.  If the pathname where it is found matches the
            pathname associated with a built‐in command, the built‐
            in  command  is  executed.   If the directory where the
            command is found is listed in the [1mFPATH  [22mvariable,  the
            file  is  read  into the shell like a dot script, and a
            function by that name is invoked.  Once a  pathname  is
            found,  [1mksh  [22mremembers  its  location  and  only checks
            relative directories in [1mPATH [22mthe next time the  command
            name  is used.  Assigning a value to [1mPATH [22mcauses [1mksh [22mto
            forget the location of all command names.

          · The [1mFPATH [22mvariable is  searched  and  files  found  are
            treated as described above.

       The  first  argument  of  the  [1mcommand  [22mbuilt‐in,  described
       earlier,  skips  the  checks  for  reserved  words  and  for
       function  definitions.   In  all other ways, [1mcommand [22mbehaves
       like a built‐in that is not associated with a pathname.   As
       a  result,  if  the  first  argument of [1mcommand [22mis a special
       built‐in, the special properties of  this  built‐in  do  not
       apply.   For  example,  whereas,  [1mexec 3< foo  [22mwill  cause a
       script  containing  it  to  abort   if   the   open   fails,
       [1mcommand exec 3< foo  [22mresults  in  a non‐zero exit status but
       does not abort the script.

       You can get a complete list of the special built‐in commands
       with  [1mbuiltin ‐s[22m.   In  addition  [1mbuiltin  [22mwithout arguments
       gives a list of the current built‐ins and the pathname  that
       they  are  associated  with.   A  built‐in  can  be bound to
       another pathname by giving the pathname  for  the  built‐in.
       The  basename  of  this path must be the name of an existing
       built‐in for this to succeed.  Specifying the  name  of  the
       built‐in without a pathname causes this built‐in to be found
       before a path search.  A built‐in can be deleted   with  the
       [1m−d [22moption.

       On  systems  with  run  time  loading of libraries, built‐in
       commands can  be  added  with  the  [1mbuiltin  [22mcommand.   Each
       command  that  is  to  be  built‐in  must  be written as a C
       function whose name is of the form [1mb_[4m[22mname[24m, where [4mname[24m is the
       name  of the built‐in that is to be added.  The function has
       the same argument calling convention  as  [1mmain[22m.   The  lower
       eight  bits  of  the return value become the exit status for
       this  built‐in.   Builtins  are  added  by  specifying   the
       pathname  of  the library as an argument to the [1m−f [22moption of
       [1mbuiltin[22m.

       The built‐in command, [1mwhence[22m, when used with the [1m−v  [22moption,
       tells  how  a given command is bound.  A line is printed for
       each argument to [1mwhence [22mtelling what would  happen  if  this
       argument  were  used  as  a  command  name.   It  reports on
       reserved words, aliases, built‐ins, and functions.   If  the
       command  is  none  of  the above, it follows the path search
       rules and prints the full path‐name, if  any,  otherwise  it
       prints an error message.

       [4m3.15[24m  [4mSymbolic[24m [4mNames[0m

       To   avoid  implementation  dependencies,  [1mksh  [22maccepts  and





       generates symbolic names for built‐ins  that  use  numerical
       values  in  the  Bourne  shell.   The [1m−S [22moption of the [1mumask[0m
       built‐in command accepts and displays default file  creation
       permissions   symbolically.    It  uses  the  same  symbolic
       notation as the [1mchmod [22mcommand.

       The [1mtrap [22mand [1mkill [22mbuilt‐in commands allows the signal  names
       to  be  given  symbolically.  The names of signals and traps
       corresponding to signals are the same  as  the  signal  name
       with the [1mSIG [22mprefix removed.  The trap [1m0 [22mis named [1mEXIT[22m.

       [4m3.16[24m  [4mAdditional[24m [4mVariables[0m

       In  addition  to  the  variables  discussed earlier, [1mksh [22mhas
       other variables that it  handles  specially.   The  variable
       [1mRANDOM [22mproduces a random number in the range 0 to 32767 each
       time it is referenced.  Assignment to this variable sets the
       seed for the random number generator.

       The parameter [1mPPID [22mis used to generate the process id of the
       process which invoked this shell.

       [4m3.17[24m  [4mAdded[24m [4mTraps[0m

       A new trap named [1mERR [22mhas been added.  This trap  is  invoked
       whenever  the  shell  would  exit if the [1m−e [22moption were set.
       This trap is used by Fourth Generation Make[16]  which  runs
       [1mksh [22mas a co‐process.

       A  trap  named [1mDEBUG [22mgets executed after each command.  This
       trap can be used for debugging and other purposes.

       The [1mKEYBD [22mtrap was described earlier.

       [4m3.18[24m  [4mDebugging[0m

       The primary method for debugging Bourne shell scripts is  to
       use  the [1m−x [22moption to enable the execution trace.  After all
       the expansions have been performed, but before each  command
       is executed, the trace writes to standard error the name and
       arguments of each command preceded by a [1m+[22m.  While the  trace
       is  very  useful,  there  is no way to find out what line of
       source a given trace line corresponds to.  With [1mksh [22mthe  [1mPS4[0m
       variable   is  evaluated  for  parameter  expansion  and  is
       displayed before each command, instead of the [1m+[22m.

       The [1mLINENO [22mvariable  is  set  to  the  current  line  number
       relative to the beginning of the current script or function.
       It is most useful as part of the [1mPS4 [22mprompt.

       The [1mDEBUG [22mtrap can be used to  write  a  break  point  shell
       debugger   in  [1mksh[22m.   An  example  of  such  a  debugger  is
       [1mkshdb[22m.[17]

       [4m3.19[24m  [4mTiming[24m [4mCommands[0m

       Finding the time it takes to execute  commands  has  been  a
       serious  problem  with  the  Bourne  shell.   Since the [1mtime[0m
       command is not part of the  language,  it  is  necessary  to
       write  a  script  in order to time a [1mfor [22mor [1mwhile [22mloop.  The
       extra time in invoking the shell and processing  the  script





       is accumulated along with the time to execute the script.

       More seriously, the Bourne shell does not give correct times
       for pipelines.  The reason for this is that  the  times  for
       some  members  of  a pipeline are not counted when computing
       the time.  As an extreme example, running [1mtime [22mon the script
                  [1mcat < /dev/null | sort ‐u bigfile | wc[0m
       with the Bourne shell will show very little user and  system
       time no matter how large [1mbigfile [22mis.

       To  correct  these  problems,  a reserved word [1mtime [22mhas been
       added to replace the [1mtime [22mcommand.  Any function, command or
       pipeline  can  be  preceded  by this reserved word to obtain
       information about  the  elapsed,  user,  and  system  times.
       Since  I/O  redirections  bind  to the command, not to [1mtime[22m,
       parentheses  should  be  used   to   redirect   the   timing
       information which is normally printed on file descriptor 2.


       [4m4.[24m  [4mSECURITY[0m

       There  are  several  documented problems associated with the
       security of  shell  procedures[18].   These  security  holes
       occur   primarily   because   a   user  can  manipulate  the
       [4menvironment[24m  to  subvert  the  intent  of  a  [4msetuid[24m   shell
       procedure.   Sometimes,  shell procedures are initiated from
       binary programs, without the author’s awareness, by  library
       routines which invoke shells to carry out their tasks.  When
       the binary program is run [4msetuid[24m then  the  shell  procedure
       runs  with  the  permissions  afforded  to  the owner of the
       binary file.

       In the Bourne shell, the [1mIFS [22mparameter is used to split each
       word  into separate command arguments.  If a user knows that
       some [4msetuid[24m program will run [1msh ‐c /bin/pwd  [22m(or  any  other
       command  in  [1m/bin[22m)  then  the  user  sets and exports [1mIFS=/[22m.
       Instead of running [1m/bin/pwd [22mthe shell will run [1mbin [22mwith  [1mpwd[0m
       as  an  argument.   The user puts his or her own [1mbin [22mprogram
       into the current directory.  This program can create a  copy
       of  the  shell,  make  this  shell  [4msetuid[24m, and then run the
       [1m/bin/pwd [22mprogram so that the original program  continues  to
       run  successfully.  This kind of penetration is not possible
       with [1mksh [22msince the [1mIFS [22mparameter only splits arguments  that
       result from command or parameter substitution.

       Some  [4msetuid[24m  programs  run  programs using [4msystem()[24m without
       giving the  full  pathname.   If  the  user  sets  the  [1mPATH[0m
       variable so that the desired command will be found in his or
       her local bin, then the same technique described  above  can
       be  employed  to  compromise the security of the system.  To
       close up this and  other  security  holes,  [1mksh  [22mresets  the
       effective  user  id  to  the  real user id and the effective
       group id to the real group id unless the  [4mprivileged[24m  option
       ([1m−p[22m)   is  specified  at  invocation.   In  this  mode,  the
       [1mprivileged  [22mmode,  the  [1m.profile  [22mand  [1mENV  [22mfiles  are   not
       processed.   Instead, the file [1m/etc/suid_profile [22mis read and
       executed.  This gives  an  administrator  control  over  the
       environment  to set the [1mPATH [22mvariable or to log setuid shell
       invocations.  Clearly security of the system is  compromised
       if [1m/etc [22mor this file is publicly writable.






       Some  versions  of  the  UNIX  operating system look for the
       characters [1m#!  [22mas the first two characters of an  executable
       file.   If these characters are found, then the next word on
       this line is taken as the interpreter  to  invoke  for  this
       command  and  the interpreter is [4mexec[24med with the name of the
       script as argument zero and argument one.  If the [4msetuid[24m  or
       [4msetgid[24m  bits  are  on for this file, then the interpreter is
       run with the effective uid and/or gid set accordingly.  This
       scheme has three major drawbacks.  First of all, putting the
       pathname of the interpreter into the script makes the script
       less  portable  since  the interpreter may be installed in a
       different directory on another system.  Secondly, using  the
       [1m#!  [22mnotation forces an [1mexec [22mof the interpreter even when the
       call is invoked from the interpreter  which  it  must  exec.
       This  is inefficient since [1mksh [22mcan handle a failed exec much
       faster than starting up again.  More importantly, [4msetuid[24m and
       [4msetgid[24m  procedures provide an easy target for intrusion.  By
       linking a [4msetuid[24m or [4msetgid[24m procedure  to  a  name  beginning
       with  a [1m− [22mthe interpreter is fooled into thinking that it is
       being invoked with a command line  option  rather  than  the
       name of a file.  When the interpreter is the shell, the user
       gets a privileged interactive shell.  There is code  in  [1mksh[0m
       to guard against this simple form of intrusion.

       A  more  reliable way to handle [4msetuid[24m and [4msetgid[24m procedures
       is provided with [1mksh[22m.  The technique does  not  require  any
       changes   to   the  operating  system  and  provides  better
       security.  Another advantage to this method is that it  also
       allows  scripts  which  have  execute permission but no read
       permission  to  run.   Taking  away  read  permission  makes
       scripts more secure.

       The  method  relies on a setuid [1mroot [22mprogram to authenticate
       the request and exec the shell with the correct mode bits to
       carry  out  the  task.   This  shell  is  invoked  with  the
       requested file already open for  reading.   A  script  which
       cannot  be opened for reading or which has its setuid and/or
       setgid bits turned on causes this setuid [1mroot [22mprogram to get
       [1mexec[22med.   For  security  reasons,  this program is given the
       full  pathname  [1m/etc/suid_exec[22m.   A   description   of   the
       implementation of the [1m/etc/suid_exec [22mprogram can be found in
       a separate paper[19].


       [4m5.[24m  [4mCODE[24m [4mCHANGES[0m

       [1mksh [22mis written in ANSI‐C as a reusable  library.   The  code
       can  be compiled with C++ and older K&R C as well.  The code
       uses the IEEE  POSIX  1003.1  and  ISO  9945‐1  standard[20]
       wherever  possible  so that [1mksh [22mshould be able to run on any
       POSIX compliant system.  In  addition,  it  is  possible  to
       compile [1mksh [22mfor older systems.

       Unlike earlier version of the Bourne shell, [1mksh [22mtreats eight
       bit  characters  transparently  without  stripping  off  the
       leading  bit.  There is also a compile time switch to enable
       handling multi‐byte and multi‐width characters sets.

       On systems with dynamic libraries, it  is  possible  to  add
       built‐in  commands  at  run  time  with the built‐in command
       [1mbuiltin [22mdescribed earlier.  It is also possible to embed [1mksh[0m





       in applications in a manner analogous to [1mtcl[22m.


       [4m6.[24m  [4mEXAMPLE[0m

       An  example  of  a  [1mksh  [22mscript is included in the Appendix.
       This one page program  is  a  variant  of  the  UNIX  system
       [1mgrep[22m(1)  program.  Pattern matching for this version of [1mgrep[0m
       means shell patterns.

       The first half uses the [1mgetopts [22mcommand to find  the  option
       flags.   Nearly  all  options  have  been  implemented.  The
       second half goes through each line of each file to look  for
       a pattern match.

       This  program  is not intended to serve as a replacement for
       [1mgrep [22mwhich has been highly tuned for performance.   It  does
       illustrate  the  programming  power  of  [1mksh[22m.   Note that no
       auxiliary processes are spawned  by  this  script.   It  was
       written  and debugged in under two hours.  While performance
       is acceptable for small files, this program runs at only one
       tenth the speed of [1mgrep [22mfor large files.


       [4m7.[24m  [4mPERFORMANCE[0m

       [1mksh  [22mexecutes  many  scripts faster than the System V Bourne
       shell; in some cases  more  than  10  times  as  fast.   The
       primary reason for this is that [1mksh [22mcreates fewer processes.
       The time to execute a built‐in command or a function is  one
       or  two  orders of magnitude faster than performing a [1mfork[22m()
       and  [1mexec[22m()  to  create   a   separate   process.    Command
       substitution  and  commands inside parentheses are performed
       without  creating  another  process,  unless  necessary   to
       preserve correct behavior.

       Another  reason  for  improved performance is the use of the
       [1msfio[22m[21], library for I/O.  The [1msfio [22mlibrary buffers all I/O
       and  buffers are flushed only when required.  The algorithms
       used in [1msfio [22mperform better  than  traditional  versions  of
       standard  I/O so that programs that spend most of their time
       formatting output may actually perform better than  versions
       written in C.

       Several of the internal algorithms have been changed so that
       the  number  of  subroutine  calls  has  been  substantially
       reduced.  [1mksh [22muses variable sized hash tables for variables.
       Scripts that rely heavily on referencing  variables  execute
       faster.   More  processing  is  performed  while reading the
       script so that execution time is saved while running  loops.
       These changes are not noticeable for scripts that [1mfork() [22mand
       run processes, but they reduce the time  that  it  takes  to
       interpret commands by more than a factor of two.

       Most   importantly,   [1mksh   [22mprovide   mechanisms   to  write
       applications that do not require  as  many  processes.   The
       arithmetic provided by the shell eliminates the need for the
       [1mexpr  [22mcommand.    The   pattern   matching   and   substring
       capabilities eliminate the need to use [1msed [22mor [1mawk [22mto process
       strings.






       The architecture of [1mksh  [22mmakes  it  easy  to  make  commands
       built‐ins  without  changing  the semantics at all.  Systems
       that have run‐time binding of libraries  allow  applications
       to  be  sped  up by supplying the critical programs as shell
       built‐in commands.  Implementations on other systems can add
       built‐in  commands  at  compile  time.   The  procedure  for
       writing built‐in commands that can be loaded at run time  is
       in a separate document.[22],


       [4m8.[24m  [4mCONCLUSION[0m

       The  1988  version  of  [1mksh [22mhas tens of thousands of regular
       users and is a suitable replacement for  the  Bourne  shell.
       The  1993  version  of  [1mksh [22mis essentially upward compatible
       with both the 1988 version of [1mksh [22mand with the  recent  IEEE
       POSIX  and ISO shell standard.  The 1993 version offers many
       advantages for programming applications,  and  it  has  been
       rewritten  so  that it can be used in embedded applications.
       It also offers improved performance.



       MH‐11267‐DGK‐dgk              David G. Korn










































                                 [4mAPPENDIX[0m

            function grep
            {
                    #
                    #       SHELL VERSION OF GREP
                    #
                    vflag= xflag= cflag= lflag= nflag=
                    set ‐f
                    while   ((1))                           # look for grep options
                    do      case    "$1" in
                            ‐v*)    vflag=1;;
                            ‐x*)    xflag=1;;
                            ‐c*)    cflag=1;;
                            ‐l*)    lflag=1;;
                            ‐n*)    nflag=1;;
                            ‐b*)    print ’b option not supported’;;
                            ‐e*)    shift;expr="$1";;
                            ‐f*)    shift;expr=$(< $1);;
                            ‐*)     print $0: ’unknown flag’;return 2;;
                            *)
                                    if      test "$expr" = ’’
                                    then    expr="$1";shift
                                    fi
                                    test "$xflag" || expr="*${expr}*"
                                    break;;
                            esac
                            shift                           # next argument
                    done
                    noprint=$vflag$cflag$lflag              # don’t print if these flags are set
                    integer n=0 c=0 tc=0 nargs=$#           # initialize counters
                    for i in "$@"                           # go thru the files
                    do      if      ((nargs<=1))
                            then    fname=’’
                            else    fname="$i":
                            fi
                            test "$i"  &&  exec 0< $i       # open file if necessary
                            while   read ‐r line            # read in a line
                            do      let n=n+1
                                    case    "$line" in
                                    $expr)                  # line matches pattern
                                            test "$noprint" || print ‐r ‐‐ "$fname${nflag:+$n:}$line"
                                            let c=c+1 ;;
                                    *)                      # not a match
                                            if      test "$vflag"
                                            then    print ‐r ‐‐ "$fname${nflag:+$n:}$line"
                                            fi;;
                                    esac
                            done
                            if      test "$lflag" && ((c))
                            then    print ‐r ‐‐ "$i"
                            fi
                            let tc=tc+c n=0 c=0
                    done
                    test "$cflag" && print $tc              #  print count if cflag is set
                    let tc                                  #  set the return value
            }











































































                                [4mREFERENCES[0m

         7. S. R. Bourne, [4mAn[24m [4mIntroduction[24m [4mto[24m [4mthe[24m [4mUNIX[24m  [4mShell[24m,  Bell
            System  Technical  Journal, Vol. 57, No. 6, Part 2, pp.
            1947‐1972, July 1978.

         8. W. Joy, [4mAn[24m [4mIntroduction[24m [4mto[24m [4mthe[24m [4mC[24m [4mShell[24m,  Unix  Program-
            mer’s Manual, Berkeley Software Distribution, Universi-
            ty of California, Berkeley, 1980.

         9. Morris Bolsky and David Korn, [4mThe[24m [4mKornShell[24m [4mCommand[24m [4mand[0m
            [4mProgramming[24m [4mLanguage[24m, Prentice Hall, 1989.

        10. Jason  Levitt,  [4mThe[24m  [4mKorn[24m  [4mShell:[24m [4mAn[24m [4mEmerging[24m [4mStandard[24m,
            UNIX/World, pp. 74‐81, September 1986.

        11. Rich Bilancia, [4mProficiency[24m [4mand[24m [4mPower[24m [4mare[24m [4mYours[24m [4mWith[24m [4mthe[0m
            [4mKorn[24m [4mShell[24m, UNIX/World, pp. 103‐107, September 1987.

        12. John  Sebes, [4mComparing[24m [4mUNIX[24m [4mShells,[24m UNIX Papers, Edited
            by the Waite Group, Howard W. Sams & Co., 1987.

        13. T. A. Dolotta and J. R. Mashey, [4mUsing[24m [4mthe[24m  [4mshell[24m  [4mas[24m  [4ma[0m
            [4mPrimary[24m  [4mProgramming[24m  [4mTool,[24m  Proc.  2nd.  Int. Conf. on
            Software Engineering, 1976, pages 169‐176.

        14. J. S. Pendergrast, [4mWKSH[24m [4m‐[24m  [4mKorn[24m  [4mShell[24m  [4mwith[24m  [4mX‐Windows[0m
            [4mSupport[24m, USL. 1991.

        15. American  National  Standard  for Information Systems −
            Programming Language − C, ANSI X3.159‐1989.

        16. G. S. Fowler, [4mThe[24m [4mFourth[24m [4mGeneration[24m  [4mMake,[24m  Proceedings
            of the Portland USENIX meeting, pp. 159‐174, 1985.

        17. Bill  Rosenblatt,  [4mDebugging[24m  [4mShell[24m [4mScripts[24m [4mwith[24m [1mkshdb[22m,
            Unix World, Volume X, No. 5, 1993.

        18. F. T. Grampp and R. H. Morris,  [4mUNIX[24m  [4mOperating[24m  [4mSystem[0m
            [4mSecurity,[24m AT&T Bell Labs Tech. Journal, Vol. 63, No. 8,
            Part 2, pp. 1649‐1671, 1984.

        19. D. G Korn [4mParlez‐vous[24m [4mKanji?[24m  TM‐59554‐860602‐03, 1986.

        20. [4mPOSIX[24m [4m−[24m [4mPart[24m [4m1:[24m [4mSystem[24m [4mApplication[24m  [4mProgram[24m  [4mInterface,[0m
            IEEE Std 1003.1‐1990, ISO/IEC 9945‐1:1990.

        21. David  Korn  and  Kiem‐Phong  Vo,  [4mSFIO[24m  [4m‐[24m  [4mA[24m [4mSafe/Fast[0m
            [4mString/File[24m [4mI/O,[24m Proceedings of the Summer Usenix,  pp.
            235‐255, 1991.

        22. David Korn, [4mGuidelines[24m [4mfor[24m [4mwriting[24m [1mksh‐93 [4m[22mbuilt‐in[24m [4mcom-[0m
            [4mmands,[24m to be published, 1994.













