bdw@chinet.UUCP (Bill Wisner) (02/14/86)
We have ksh on chinet, and this document has been floating around for a while. It is a description/abstract/explanation of ksh, the Korn Shell. It does NOT include information on licensing, etc, but I may be able to post that within a few days (after talking to root).. --cut here---------------------and here--------------------here, too-- 1. Introduction Over the past two or three years several papers have been written describing new command interpreters for the UNIX system. These papers can be divided into two categories: Those that improve the shell as a programming language, and those that improve the shell as a command interpreter. Most of the papers fall into the latter category. In particular, vicmd[3] preserves the friendly environment of vi (from which this memo was entered), and adds a facility for convenient command entry. An emacs oriented shell has also been written by Veach[4]. The 2dsh[5] shell allows the setup of more complicated networks of processes than just pipelines. The See-shell[6] proposes a Small-Talk like interface[7] suitable for bit-mapped terminals such as the BLIT[8] and the Apollo[9]. Perhaps the most widely used shell, other than the Bourne shell, is Csh, which runs under the Berkeley UNIX operating system. Csh has many attractive command interpreter features not currently in the Bourne shell; most notably, job control, history, arithmetic, and command name aliasing. On the other hand, many people (including this author), think that the Bourne shell is superior as a programming language. The history mechanism of Csh has recently been added as a local modification to the Bourne shell by J. L. Steffen[10]. The use of the shell as a programming language has been described by Dolotta and Mashey[11] and has been used by many people here at Bell Laboratories. Kolettis[12] presented extensions to the Bourne shell to provide message passing facilities and other inter-process communication and synchronization features. The Form shell[13] added form entry/edit capabilities to the Bourne shell. A proposal for a more programming language oriented shell has been proposed by Sturzenbecker[14]. - 2 - This memo describes Ksh, aka the Korn-shell. This memo is not a tutorial, only an introduction. Ksh is a direct descendant of the Form shell with most of the form entry/edit features removed and with many new features added. The primary focus of this work has been to provide an enhanced programming environment in addition to the major command entry features of Csh. Improved performance has been a major objective. Many of the additions have been provided so that medium sized programming tasks can be written at the shell level without a serious performance penalty. A concerted effort has been made to achieve System V Bourne shell compatibility so that scripts written for the Bourne shell can run without modification with Ksh. The description of features in this memo assumes that the reader is already familiar with the Bourne shell. A version of Ksh has been run on several machines including a VAX 11/780, VAX 11/750, PDP-11/70, PDP-11/23, IBM-370, AT&T 3B20, and Apollo Domain. It has been run on top of several versions of the UNIX operating system including System III, System V, BSD 4.1, BSD 4.1c, 4.2, and Apollo UNIX. The shell is in use in several centers at AT&T Bell Laboratories, and has been installed as /bin/sh on VAXEN running System V, BSD 4.1., BSD 4.2 and on a 3B-20 running System V. 2. Shell Variables The ability to define and use variables to store and retrieve values is an important feature in most programming languages. Ksh has variables with identifiers that follow the same rules as the Bourne shell. Since all variables have string representations, there is no need to specify the type of each variable in the shell. In Ksh, each variable can have one or more attributes that control the internal representation of the variable, the way the variable is printed, and its access or scope. Two of the attributes, readonly and export, are available in the Bourne shell. The typeset built-in command of Ksh assigns attributes to variables. The list of attributes appears in the manual page. The unset built-in of the Ksh removes values and attributes of parameters. 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. There are three attributes for field justification, as might be needed for formatting a report. For each of these attributes, the first time an assignment is made to the variable its size is remembered. Each assignment causes - 3 - justification of the field, truncating if necessary. Assignment to fixed sized variables provides a simple way to generate a substring consisting of a fixed number of characters from the beginning or end of a string. The attributes -u and -l, are 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 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 : and prints fields 4 and 2 in upper case in columns 1-15, left justified, and columns 20-25 right-justified respectively. typeset -Lu f4=123456789012345 # 15 character left justified typeset -Ru f2=123456 # 6 character right justified IFS=: set -f # skip file name generation while read -r f1 f2 f3 f4 f5 # read line, split into fields do print -r "$f4 $f2" # print fields 4 and 2 done The integer attribute, -i, causes the variable to be internally represented as an integer. The first assignment to an integer variable determines the output base (see below). This base will be used whenever the variable is printed. Assignment to integer typed variables result in arithmetic evaluation, as described below, of the right hand side. Ksh allows one-dimensional arrays in addition to simple variables. Any variable can become an array by referring to it with a subscript. All elements of an array need not exist. Subscripts for arrays must evaluate to an integer between 0 and 127, otherwise an error results. Evaluation of subscripts is described in the next section. Attributes apply to the whole array. Assignments to array variables are made with the typeset built-in. Referencing of subscripted variables requires the character $, 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: ${name[subscript]}. A subscript value of * or @ can be used to generate all elements of an array, as they are used for expansion of positional parameters. - 4 - A few additional operations are available on shell variables. ${#name} will be then length in bytes of $name. For an array variable ${#name[*]} gives the number of elements in the array. There are two parameter substitution modifiers that have been added to strip off leading and trailing substrings during parameter substitution. The modifier # strips off from the left and the modifier % strips off from the right. For example, if the shell variable i has value file.c, then the expression ${i%.c} has value file. The substring built-in has been added to Ksh to enable the user to generate a substring of a given string. The built-in allows the user to specify an expression to be deleted from the left and right ends of the string. The resulting substring is printed out. Command substitution can be used to assign the output of substring to a shell variable. 3. Arithmetic Evaluation The built-in command, let, provides the ability to do integer arithmetic. All arithmetic evaluations are performed using long arithmetic. Arithmetic constants are written as base#number where base is a decimal integer between two and thirty-six and number is any positive integer. Base ten is used if no base is specified. Arithmetic expressions are made from constants, variables, and one or more of the fourteen operators listed in the manual page. Operators are evaluated in order of precedence. Parentheses may be used for grouping. A variable does not have to have an integer attribute to be used within an arithmetic expression. The name of the variable is replaced by its value within an arithmetic expression. The statement let x=x+1 can be used to increment a variable x. Note that there is no space before or after the operators + and =. This is because each argument to let is an expression to evaluate. The last expression determines the value returned by let. If the last expression evaluates to a non-zero value, the let returns true. Otherwise, let returns false. Note that many of the arithmetic operators have special meaning to the shell and must be quoted. Since this can be burdensome, an alternate form of arithmetic evaluation syntax has been provided. For any command that begins with ((, all the characters until the matching )) are treated as - 5 - a quoted arithmetic expression. The double parentheses usually avoids incompatibility with the Bourne shell's use of parentheses for grouping a set of commands to be run in a sub-shell. Expressions inside double parentheses can contain blanks and special characters without quoting. More precisely, (( ... )) is equivalent to let " ... " The following script prints the first n lines of its standard input onto its standard output, where n is supplied as an argument or is 20 if omitted. typeset -i n=${1-20} # set n while read -r line && (( (n=n-1)>=0 ))# at most n lines do print -r - "$line" done 4. Functions and Command Aliasing Two new mechanisms have been provided for creating pseudo- commands, i. e., things that look like commands, but do not always create a process. The first technique is called command name aliasing. As a command is being read, the command name is checked against a list of alias names. If it is found, the name is replaced by the text associated with the alias and then rescanned. The text of an alias is not checked for aliases so recursive definitions are not allowed. Aliases are defined with the alias built-in. The form of an alias command is: alias name=value Except for the first character, which must be printable, the alias name must be a valid identifier. The replacement text, value, can contain any valid shell script, including metacharacters such as pipe symbols and i/o-redirection. Aliases can be used to redefine built-in commands so that the alias alias test=./test can be used to look for test in your current working directory rather than using the built-in test command. Keywords such as for and while cannot be changed by aliasing. The command alias, without arguments, generates a list of aliases and corresponding texts. The unalias command removes the name and text of an alias. - 6 - Aliases are used to save typing and to improve readability of scripts. For example, the alias alias integer='typeset -i' allows integer the variables i and j to be declared and initialized with the command integer i=0 j=1. One frequent use of aliases is to alias a command name to the full path-name of the program. This eliminates the path search but requires knowledge of where that program will be stored. To reduce the amount of path searching, tracked aliases have been introduced. A tracked alias is not given a value. Its value is defined at the first reference by a path-search as the full path-name equivalent of the name, and remains defined until the PATH variable is changed. Programs found in directories that do not begin with / that occur earlier in the path-search than the value of the tracked alias, take precedence over tracked aliases. Tracked aliases provide an alternative to the Csh command hashing facility. Tracked aliases do not require time for initialization and allow for new commands to be introduced without the need for re-hashing. An option to the shell allows all command names that are valid alias names to become tracked aliases. Functions are more general than aliases but also more costly. Functions definitions are of the form function name { any shell script } The function is invoked by writing name and optionally following it with arguments. Positional parameters are saved before each function call and restored when completed. Functions are executed in the current shell environment and can share named variables with the calling program. The return built-in can be used to cause the function to return to the statement following the point of invocation. By default, variables are inherited by the function and shared by the calling program. However, environment substitutions preceding the function call apply only to the scope of the function call. Also, variables defined with the typeset, built-in command are local to the function that they are declared in. Thus, for the function defined function name { typeset -i x=10 let z=x+y - 7 - print $z } invoked as y=13 name, x and y are local variables with respect to the function name while z is global. Alias and function names are never directly carried across separate invocations of Ksh, but can be passed down to sub- shells. The -x flag is used with alias to carry aliases to sub-shells while the -fx flags of typeset are used to do the same for functions. Several of the UNIX commands can be aliased to Ksh built- ins. Some of these are automatically set each time the shell is invoked. In addition, about twenty frequently used UNIX commands are set as tracked aliases. Each user can create a file for aliases and functions. Aliases and functions that are to be available for all shell invocations should be put into the Ksh startup file. By setting and exporting the environment variable, ENV, to the name of this file, the aliases and functions will be defined each time Ksh is invoked. The value of the ENV variable undergoes macro and command substitution prior to its use. Since the ENV file is not invoked automatically for a log in shell, it is usually necessary to include the line eval . $ENV in your .profile file. 5. Input and Output An extended I/O capability has been added to enhance the use of the shell as a programming language. The Bourne shell has a built-in read for reading lines from file descriptor 0, but does not have any internal output mechanism. As a result, the echo(1) command has been used to produce output for a shell procedure. This is inefficient and also restrictive. For example, there is no way to read in a line from a terminal and to echo the line exactly as is. In the Bourne shell, the read built-in cannot be used to read lines that end in `\', and the echo command will treat certain sequences as control sequences. In addition, there is no way to have more than one file open at any time for reading. Ksh has options on the read command to specify the file descriptor for the input. The exec built-in can be used to open and close file streams. The -r option allows a `\' at the end of an input line to be treated as a regular character rather than the line continuation character. The first argument of the read command can be followed by a ? and a prompt to produce a prompt at the terminal before the read. If the input is not from a terminal device then the - 8 - prompt is not issued. The Ksh built-in, print, is used to output characters to the terminal or to a file. Again, it is possible to specify the file descriptor number as an option to the command. Ordinarily, the arguments to this command are processed the same as for echo(1). However, the -r flag can be used to output the arguments without any special meaning. The -n flag can be used here to suppress the trailing new-line that is ordinarily appended. To improve performance of existing shell programs, an alias for echo is defined by the shell when it is invoked. For the AT&T-UNIX version, the alias is alias echo='print -', where the - signifies that there are no more options, while for the Berkeley UNIX version alias echo='print -R', where the -R option allows only the -n flag to be recognized as the next argument, gives the desired result. The shell is frequently used as a programming language for interactive dialogues. The select statement 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, PS3, 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 REPLY variable is used to store the user entered reply. 6. Command Re-entry An interactive shell saves the commands you type at a terminal in a file. If the variable HISTFILE is set to the name of a file to which the user has write access, then the commands are stored in this history file. Otherwise the file $HOME/.history is checked for write access and if this fails an unnamed file is used to hold the history lines. This file is truncated if this is a top level shell. The number of commands accessible to the user, is determined by the value of the HISTSIZE variable at the time the shell is invoked. The default value is 64. A command may consist of one or more lines since a compound command is considered one command. If the character ! is placed within the primary prompt string, then it is replaced by the command number each time the prompt is given. Whenever the file is named, all shells which use this file share access to the same history. - 9 - A built-in command fc (fix command) is used to list and/or edit any of these saved 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. The option -l is used to specify listing of previous commands. 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 Ksh. The editor to be used may be specified with the option -e and following it with the editor name. If this option is not specified, the value of the shell variable FCEDIT is used as the name of the editor, providing that this variable has non-null value. If this variable is not set, or is null, and the -e option has not been selected, then /bin/ed is used. When editing has been complete, the edited text automatically becomes the input for Ksh. As this text is read by Ksh, it is echoed onto the terminal. An editor name of - is used to bypass the editing and just re-execute the command. In this case only a single command can be specified as the range and an optional argument of the form old=new may be added which requests a simple string substitution prior to evaluation. A convenient alias, alias r='fc -e -' has been pre-defined so that the single key-stroke r can be used to re-execute the previous command and the key-stroke sequence, r abc=def c can be used to re-execute the last command that starts with the letter c with the first occurrence of the string abc replaced with the string def. Typing r c > file re-executes the most recent command starting with the letter c, with standard output redirected to file. 7. In-line editing 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. Ksh offers 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 - 10 - portion visible. Editing can be performed on this window until the return key is pressed. The editing modes have commands that access the history file in which previous commands are saved. A user can copy any of the most recent HISTSIZE commands 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 termcap database. 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. There is a choice of editor options. The emacs, gmacs, or vi option is selected by turning on the corresponding option of the set command. If the value of the EDITOR or VISUAL ends any of these suffixes the corresponding options is turned on. A large subset of each of each of these editors features are available within the shell. Additional functions, such as file name completion, have also been added. The code for the emacs and gmacs editing option was supplied by Mike Veach. In the emacs or gmacs mode 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 command ^T. Control keys and escape sequences are used for cursor positioning and control functions. The available editing functions are listed in the manual page. The code for the vi editing option was supplied by Pat Sullivan. The vi editing mode starts in insert mode and enters control mode when the user types ESC( 033). The return 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 vi commands are available. The k and j command that normally move up and down by one line, move up and down one command in the history file, copying the command at 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 viraw option of the set command, which always uses raw or cbreak mode, must be used in this case. - 11 - 8. Job Control The job control mechanism is almost identical to the version found in Csh of the Berkeley UNIX operating system, version 4.1. 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 monitor option which when enabled will report the progress of background jobs and enable the user to kill jobs by job number or job name. An interactive shell associates a job with each pipeline typed in from the terminal and assigns them 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 Ksh creates 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 ^Z (control-Z) which sends a STOP signal 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 % introduces a job name. You can refer to jobs by name or number as described in the manual page. The built-in command bg allows you to continue a job in the background, while the built-in command fg allows 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 jobs that lists the status of all running and stopped jobs. In addition, you are notified of the change of state of any background jobs just before each prompt. When you try to leave the shell while jobs are stopped or running, you will receive a message from Ksh. If you ignore this message and try to leave again, all stopped processes will be terminated. A built-in version of kill makes it possible to use job numbers as targets for signals. Signals can be selected by number or name. The name of the signal is the name found in the include file /usr/include/signal.h with the prefix SIG - 12 - removed. The list of valid signal names can be generated with the -l flag of kill. 9. Miscellaneous Ksh has several additional features to enhance functionality and performance. This section lists most of these features. 9.1 Tilde substitution The character 8 at the beginning of a word has special meaning to Ksh. If the characters after the 8 up to a / match a user login name in the /etc/passwd file,9then the 8 and the name are replaced by that user's login directory. If no match is found, the original word is unchanged. A 8 by itself, or in front of a /, is replaced by the value of the HOME parameter. A 8 followed by a + or - is replaced by the value of the parameter PWD and OLDPWD respectively. Tilde substitution takes place when the script is read, not while it is executed. 9.2 Built-in I/O Redirection All built-in commands can be redirected. 9.3 Added options Several options have been added to the shell and all options have names that can be used in place of flags for setting and resetting options. The command set -o will list the current option settings. The option, -f or noglob is used to disable file name generation. It can be applied at invocation or as an option to the set command. The option ignoreeof can be used in a top-level shell to prevent ^D from logging you out. You must type exit to log out. The -h or trackall option will cause all commands whose name is a valid alias name to become a tracked alias. The job monitor option will cause a report to be printed when each background job completes. It is automatically enabled for systems that have job control. If the bgnice option is set, background jobs are run at a lower priority. - 13 - 9.4 Previous Directory Ksh remembers your last directory in the variable OLDPWD. The cd built-in can be given with argument - to return to the previous directory. Note that cd - done twice returns you to the starting directory, not the second previous directory. A directory stack can be implemented with shell internals by using an array and writing shell functions to push and pop directories from the stack. 9.5 Additional Variables and Parameters Several new parameters have special meaning to Ksh. The variable PWD is used to hold the current working directory of the shell. The command, pwd, is aliased to print - $PWD for better response. The variable OLDPWD is used to hold the previous working directory of the shell. The variable FCEDIT is used by the fc built-in described above. The variables VISUAL and EDITOR are used for determining the edit modes as described above. The variable ENV is used to define the startup file for non-login Ksh invocations. The variables HISTSIZE and HISTFILE control the size and location of the file containing commands entered at a terminal. The parameter MAILPATH is a colon ( : ) 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 ? and a prompt to be given when a change has been detected in the file. The prompt will be evaluated for macro and command substitution. The parameter MAILCHECK is used to specify the minimal interval in seconds before new mail is checked for. The variable RANDOM produces a random number each time it is referenced. Assignment to this variable sets the seed for the random number generator. The parameter PPID is used to generate the parent process id of the shell. The value of the parameter _ is the last argument of the previous command. The parameter TMOUT can be set to be the number of seconds that the shell will wait for input before terminating. - 14 - The COLS variable can be used to adjust the width of the edit window for the in-line edit modes. 9.6 Modified variables The input field separator parameter, IFS, has meaning for the read built-in, for the set built-in, and while expanding for and select lists. In all other instances it is ignored. 9.7 Timing Commands A keyword time has been added to replace the time command. Any function, command or pipeline can be preceded by this keyword to obtain information about the elapsed, user and system times. Since I/O redirection bind to the command, not to time, parenthesis should be used to redirect the timing information which is normally printed on file descriptor 2. 9.8 Command Substitution The special command substitution of the form `cat file` can be replaced by `< file`, which is faster because no separate process is created. 9.9 Whence The addition of aliases, functions, and more built-ins has made it substantially more difficult to know what a given command word really means. A built-in command, whence when used with the -v option has been provided to answer this question. A line is printed for each argument to whence telling what would happen if this argument were used as a command name. It reports on keywords, 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. 9.10 Additional test operators The operators -ot and -nt can be used to compare the modification times of two files to see which is file is older than or newer than the other. The operator -ef is used to see if two files have the same device and i-node number, i. e., a link to the same file. - 15 - 9.11 Shell Accounting There is a compile time option to the shell to generate an accounting message for each shell script. The changes needed to provide this feature were supplied by Foregger[15] and have been adopted as described in his memo. 9.12 Coded in Standard C The Bourne shell is coded in an ALGOL-68 like dialect of C. Ksh is coded in standard C. 9.13 No special meaning for ^ The Bourne shell uses ^ as an archaic synonym for |. The ^ is not a special character to Ksh. 10. Example An example of a Ksh script is included in the Appendix. This one page program is a variant of the UNIX grep(1) program. Pattern matching for this version of grep means shell patterns consisting of ?, *, and []. The first half examines option flags. Note that all options except -b 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 grep; just as an illustration of the programming power of Ksh. 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 programs, this program runs at only one tenth the speed of grep for large files. 11. Performance Ksh executes many scripts faster than the System V Bourne shell. One major reason is that many of the functions provided by echo(1) and expr(1) are built-in. The time to execute a built-in function is one or two orders of magnitude faster than performing a fork and execute of the shell. Command substitution of built-ins is performed without creating another process, and often without even creating a temporary file. Another reason for improved performance is that all I/O is buffered. Output buffers are flushed only when required. - 16 - Several of the internal algorithms have been changed so that the number of subroutine calls has been substantially reduced. Ksh uses 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. Scripts that do little internal processing and create many processes run a little slower because the time to fork Ksh is slower than for the Bourne shell. 12. Conclusion More than one thousand people have tried Ksh and use it regularly. Ksh is a suitable replacement for the Bourne shell. It offers new features, better performance, and is essentially upward compatible with the Bourne shell. Many of the known bugs of the Bourne shell have been eliminated. MH-59545-DGK-dgk D. G. Korn Copy to Members of Center 5954 Laboratory 4542 Supervision D. A. Lambeth N. J. Kolettis W. P. Weber E. G. Bradford J. L. Steffen S. L Arnold M. C. Sturzenbecker M. T. Veach J. Krist - 17 - References 1. S. R. Bourne, An Introduction to the UNIX Shell," BSTJ - Vol. 57, No. 6 part 2, pages 1947-1972. 2. W. Joy, An Introduction to the C Shell, University of California, Berkeley, 1980. 3. S. L. Arnold, Vicmd a Visual Shell for Video Terminals, TM-81-54533-12, 1981. 4. J. L. Steffen and M. T. Veach, The Edit Shell - Connecting Screen Editing with the History List, USENIX Association Toronto Proceedings, 1983. 5. M. J. Rochkind, 2dsh - An Experimental Shell for Connecting Processes With Multiple Data Streams, TM-80- 9323-3. 6. Wayne T. Wilner, See-Shell: a Graphical User-Interface for UNIX Systems, Bell Laboratories internal memorandum, 1982. 7. D. C. Smith, C. Irby, R. Kimball, and B. Verplank, Designing the Star User Interface, BYTE, April, 1982, pp. 242-282. 8. R. Pike, The Blit Programmer's manual, Bell Labs, 1982. 9. P. J. Leach, P. H. Levine, B. P. Douros, J. A. Hamilton, D. L. Nelson, and B. L. Stumfp, The Architecture of an Integrated Local Network, IEEE Journal of Selected Areas in Communications, Local Area Networks Special Issue, November 1983. 10. J. L. Steffen, An Input History for the Bourne Shell, TM-82-55426-3, 1982. 11. T. A. Dolotta and J. R. Mashey, Using the shell as a Primary Programming Tool, Proc. 2nd. Int. Conf. on Software Engineering, 1976, pages 169-176. 12. N. J. Kolettis. Extended Shell - A Potential Real Time Interpreter, TM-77-4145-01, 1977. 13. D. G. Korn and D. A. Lambeth, Form Shell, TM-80-9224-3, 1980. - 18 - 14. M. C. Sturzenbecker, A New Command Language for UNIX and related systems, TM-82-45192-3. 15. T. H. Foregger, Shell Accounting, Case 40094-21, July 1982. ABSTRACT Ksh is a command language (shell) for the UNIX* operating system. It is essentially [1]patible with the System V version of the Bourne shell [2]has many additional features, such as those found in Csh , and executes faster than either of these shells. This memo introduces many of the additional features and explains some of the reasons for the better performance. This memo assumes that the reader is already familiar with the Bourne shell. The Appendix contains a sample script written in Ksh. The manual page for the current version is also included. _____________________________________________________________________ APPENDIX # # 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`< $`;; -*) print $0: 'unknown flag';exit 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 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 if test "$noprint" = "" then print -r "$fname${nflag:+$n:}$line" fi 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 - $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 exit value -- Bill Wisner / The Computer Connection UUCP: ihnp4!chinet!bdw CIS: 76474,1213 USNail: 6290 Highway 44 Star, ID 83669 Witty Quote: If you owned the universe, where would you put it? Witty Disclaimer: When I want your opinion, I'll give it to you.