home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-12 | 54.9 KB | 2,072 lines |
- Newsgroups: comp.sources.misc
- From: sjg@zen.void.oz.au (Simon J. Gerraty)
- Subject: v25i048: pdksh - Public Domain Korn Shell, v4, Part02/09
- Message-ID: <1991Nov13.031036.15763@sparky.imd.sterling.com>
- X-Md4-Signature: 7c582cc4d925bcf5e285068e383734fd
- Date: Wed, 13 Nov 1991 03:10:36 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
- Posting-number: Volume 25, Issue 48
- Archive-name: pdksh/part02
- Environment: UNIX
-
- #! /bin/sh
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: ksh.1 sh/jobs.c sh/trace.c
- # Wrapped by kent@sparky on Tue Nov 12 20:44:32 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 2 (of 9)."'
- if test -f 'ksh.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ksh.1'\"
- else
- echo shar: Extracting \"'ksh.1'\" \(31646 characters\)
- sed "s/^X//" >'ksh.1' <<'END_OF_FILE'
- X.\" $Header: /usr/local/src/nksh/sh/RCS/ksh.1,v 3.1 88/11/22 10:44:17 egisin Exp $
- X.nr OJ 1 \" Job Control
- X.nr OE 1 \" Command Editing
- X.nr OB 1 \" BSD enhanced ulimit options
- X.ds OK [\|
- X.ds CK \|]
- X.TH KSH 1 "January 1988"
- X.SH NAME
- Xksh \- Bourne / Korn Shell (Public Domain)
- X.SH SYNOPSIS
- X\fBksh\fP
- X[\fB\-st\fP] [\fB\-c\fP \fIcommand\fP]
- X[\fIfile\fP [\fIargument ...\fP]]
- X.SH INTRODUCTION
- XThis document only summarizes the System V, release 2 shell features.
- XAll of the System V features except for ``restricted mode''
- Xare implemented.
- XSee also the BUGS section.
- X.LP
- XFeatures of the Korn shell are described in more detail.
- XOnly a subset of the Korn shell features are currently implemented.
- X.SH DESCRIPTION
- X.SS Command syntax
- XThe ``#'' character begins a one-line comment,
- Xunless the ``#'' occurs inside a word.
- XThe tokens ``;'', ``|'', ``&'', ``;;'', ``||'', ``&&'', ``('', and ``)''
- Xstand by themselves.
- XA \fIword\fP is a sequence of any other non-whitespace characters,
- Xwhich may also contain quoted strings
- X(quote character are ``\''', ``"'', ``\`'',
- Xor a matching ``${ }'' or ``$( )'' pair).
- XA \fIname\fP is an unquoted word made up of letters, digits, or ``_''.
- XAny number of whitespace characters (space and tab) may separate words and tokens.
- X.LP
- XIn the following syntax, { ... }? indicates an optional thing,
- X{ ... }* indicates zero or more repetitions, { ... | ... } indicates alternatives.
- X.de S
- X.br
- X\\$1
- X.br
- X..
- X.IP statement:
- X.S "\fB(\fP list \fB)\fP"
- X.S "\fB{\fP list \fB;\fP \fB}\fP"
- X.S "\fBfor\fP name { \fBin\fP { word }* }? \fBdo\fP list \fB;\fP \fBdone\fP"
- X.S "{ \fBwhile\fP | \fBuntil\fP } list \fB;\fP \fBdo\fP list \fB;\fP \fBdone\fP"
- X.S "\fBif\fP list \fB;\fP \fBthen\fP list \fB;\fP { \fBelif\fP list \fB;\fP \fBthen\fP list \fB;\fP }* { \fBelse\fP list \fB;\fP }?\fBfi\fP"
- X.S "\fBcase\fP name \fBin\fP { \fB(\fP word { \fB|\fP word } \fB)\fP list \fB;;\fP }* \fBesac\fP"
- X.S "\fBfunction\fP name \fB{\fP list \fB;\fP \fB}\fP"
- X.S "name \fB() {\fP list \fB;\fP \fB}\fP"
- X.S "\fBtime\fP pipe"
- XThe opening parenthesis of the pattern is optional.
- XRedirection may occur at the beginning or end of a statement.
- X.IP command:
- X.S "{ name=word }* { word }*"
- XRedirection may occur anywhere in a command.
- X.IP list:
- X.S "cond"
- X.S "cond \fB;\fP list"
- X.S "cond \fB&\fP list"
- X.IP cond:
- X.S "pipe"
- X.S "pipe \fB&&\fP cond"
- X.S "pipe \fB||\fP cond"
- X.IP pipe:
- X.S "statement { \fB|\fP statement }*"
- X.SS Alias expansion
- XAlias expansion occurs when the first word of a
- Xstatement is a defined alias,
- Xexcept when that alias is already being expanded.
- XIt also occurs after the expansion of an alias whose
- Xdefinition ends with a space.
- X.SS Shell variables
- XThe following standard special variables exist:
- X\fB!\fP, \fB#\fP, \fB$\fP, \fB\-\fP, \fB?\fP.
- X.IP "_"
- XIn interactive use this parameter is set to the last word of
- Xthe previous command. When a command is executed this parameter
- Xis set to the full path of the command and placed in the environment
- Xfor the command. See also \fBMAILPATH\fP.
- X.IP CDPATH
- XThe search path for the \fIcd\fP command.
- X.IP ENV
- XIf this variable is set at start-up
- X(after any profile files are executed),
- Xthe expanded value is used as shell start-up file.
- XIt typically contains function and alias definitions.
- X.IP FCEDIT
- XThe editor used by the \fIfc\fP command.
- X.IP IFS
- X\fIInternal field separator\fP,
- Xused during substitution and the \fIread\fP command.
- X.IP HOME
- XThe default directory for the \fIcd\fP command.
- X.IP MAIL
- XIf set, the user will be informed of the arrival of mail
- Xin the named file. This variable is ignored if
- Xthe \fBMAILPATH\fP variable is set.
- X.IP MAILCHECK
- XHow often, in seconds, the shell will check for mail in the
- Xfile(s) specified by \fBMAIL\fP or \fBMAILPATH\fP. If 0,
- Xthe shell checks before each prompt. The default is 600
- Xseconds.
- X.IP MAILPATH
- XA list of files to be checked for mail. The list is colon
- Xseparated, and each file may be followed by a \fB?\fP and
- Xa message to be printed if new mail has arrived. Command
- Xand parameter substitution is performed on the message, and
- Xthe parameter \fB$_\fP is set to the name of the file.
- XThe default message is ``you have mail in $_''.
- X.IP PATH
- XThe search path for executable commands and \fB.\fP'd files.
- X.IP PPID
- XThe process number of the parent of the shell.
- X.IP "PS1 PS2"
- X\fBPS1\fP is the primary prompt for interactive shells.
- XDollar substitution is performed, and \fB!\fP is replaced
- Xwith the command number (see \fIfc\fP).
- X.IP "PWD OLDPWD"
- XThe current and previous working directories.
- X.IP RANDOM
- XA random integer. The random number generator may be seeded
- Xby assigning an integer value to this variable.
- X.IP SECONDS
- XThe number of seconds since the shell timer was started or
- Xreset. Assigning an integer value to this variable resets
- Xthe timer.
- X.SS Substitution
- XIn addition to the System Vr2 substitutions,
- Xthe following are available.
- X.IP "$(command)"
- XLike `command`, but no escapes are recognized.
- X.IP "$(<file)"
- XEquivalent to $(cat file), but without forking.
- X.IP "${#var}"
- XThe length of the string value of \fIvar\fP,
- Xor the number of arguments if \fIvar\fP is \fB*\fP or \fB@\fP.
- X.IP "${var#pattern} ${var##pattern}"
- XIf \fIpattern\fP matches the beginning of the value of \fIvar\fP,
- Xthe matched text is deleted from the result of substitution.
- XA single \fB#\fP results in the shortest match,
- Xtwo \fB#\fP's results in the longest match.
- X.IP "${var%pattern} ${var%%pattern}"
- XLike \fB#\fP substition, but deleting from the end of the value.
- X.SS Expressions
- XExpressions can be used with the \fBlet\fP command,
- Xas numeric arguments to the \fBtest\fP command,
- Xand as the value of an assignment to an integer variable.
- X.LP
- XExpression may contain alpha-numeric variable identifiers and integer constants
- Xand may be combined with the following operators:
- X.IP "== != <= < > >= + - * / % ! ( )"
- X.SS Command execution
- XAfter evaluation of keyword assignments and arguments,
- Xthe type of command is determined.
- XA command may execute a shell function, a shell built-in,
- Xor an executable file.
- X.LP
- XAny keyword assignments are then performed according to
- Xthe type of command.
- XIn function calls assignments are local to the function.
- XAssignments in built-in commands marked with a \(dg persist,
- Xotherwise they are temporary.
- XAssignments in executable commands are exported to the sub-process
- Xexecuting the command.
- X.LP
- XEven on systems where the exec() family does not support #!
- Xnotation for scripts, ksh can be configured to fake it.
- X.LP
- XThere are several built-in commands.
- X.IP ":"
- XOnly expansion and assignment are performed.
- XThis is the default if a command has no arguments.
- X.IP ". \fIfile\fP"
- XExecute the commands in \fIfile\fP without forking.
- XThe file is searched in the directories of $PATH.
- XPassing arguments is not implemented.
- X.IP "alias [\fIname\fB=\fIvalue\fI ...]\fR"
- XWithout arguments, \fBalias\fP lists all aliases and their values.
- XFor any name without a value, its value is listed.
- XAny name with a value defines an alias, see "Alias Expansion" above.
- XKorn's tracked aliases are not implemented,
- Xbut System V command hashing is (see "hash").
- X.IP "alias -d [\fIname\fB=\fIvalue\fI ...]\fR"
- XDirectory aliases for tilde expansion, eg.
- X.br
- Xalias -d fac=/usr/local/usr/facilities
- X.br
- Xcd ~fac/bin
- X.IP "break [\fIlevels\fP]"
- X.IP "builtin \fIcommand arg ...\fP"
- X\fICommand\fP is executed as a built-in command.
- X.IP "cd [\fIpath\fP]"
- XSet the working directory to \fIpath\fP. If the parameter
- XCDPATH is set, it lists the search path for the directory
- Xcontaining \fIpath\fP. A null path means the current directory.
- XIf \fIpath\fP is missing, the home directory ($HOME) is used.
- XIf \fIpath\fP is \fB\-\fP, the previous working directory is used.
- XIf \fIpath\fP is \fB..\fP, the shell changes directory to the
- Xparent directory, as determined from the value of PWD.
- XThe PWD and OLDPWD variables are reset.
- X.IP "cd \fIold new\fP"
- XThe string \fInew\fP is substituted for \fIold\fP in the current
- Xdirectory, and the shell attempts to change to the new directory.
- X.IP "continue [\fIlevels\fP]"
- X.IP "echo ..."
- X\fIEcho\fP is replaced with the alias echo='print' in the Korn shell.
- X.IP "eval \fIcommand ...\fP"
- X.IP "exec \fIcommand arg ...\fP"
- XThe executable command is executed without forking.
- XIf no arguments are given, any IO redirection is permanent.
- X.IP "exit [\fIstatus\fP]"
- X.IP "fc [\fB\-e\fP \fIeditor\fP] [\fB\-lnr\fP] [\fIfirst\fP [\fIlast\fP]]"
- X\fIFirst\fP and \fIlast\fP select commands.
- XCommands can be selected by history number,
- Xor a string specifing the most recent command starting with that string.
- XThe \fB\-l\fP option lists the command on stdout,
- Xand \fB\-n\fP inhibits the default command numbers.
- XThe \fB\-r\fP option reverses the order of the list.
- XWithout \fB\-l\fP, the selected commands can be edited by
- Xthe editor specified with the \fB\-e\fP option, or if no \fB\-e\fP
- Xis specified,
- Xthe \fB$FCEDIT\fP editor, then executed by the shell.
- X.IP "fc \fB\-e \-\fP [\fB\-g\fP] [\fIold\fB=\fInew\fR] [\fIcommand\fP]"
- XRe-execute the selected command (the previous command by default)
- Xafter performing the optional substitution of \fIold\fP with \fInew\fP.
- XIf \fB\-g\fP is specified, all occurrences of \fIold\fP are
- Xreplaced with \fInew\fP.
- XThis command is usually accessed with the predefined alias
- Xr=``fc \-e \-''.
- X.IP "getopts"
- XSee the attached manual page.
- X.IP "hash [\fB\-r\fP] [\fIname ...\fP]"
- XWithout arguments, any hashed executable command pathnames are listed.
- XThe \fB\-r\fP flag causes all hashed commands to be removed.
- XEach \fIname\fP is searched as if it were a command name
- Xand added to the hash table if it is an executable command.
- X.IP "kill [\fB\-\fIsignal\fR] \fIprocess\fP ..."
- XSend a signal (TERM by default) to the named process.
- XThe signal may be specified as a number or a mnemonic from <signal.h>
- Xwith the SIG prefix removed.
- X.IP "let [\fIexpression ...\fP]"
- XEach expression is evaluated, see "Expressions" above.
- XA zero status is returned if the last expression evaluates
- Xto a non-zero value, otherwise a non-zero status is returned.
- XSince may expressions need to be quoted, \fI(( expr ))\fP is
- Xsyntactic sugar for \fIlet "expr"\fP.
- X.IP "print [\fB\-nreu\fIn\fR] [\fIargument ...\fP]"
- X\fBPrint\fP prints its arguments on the standard output,
- Xseparated by spaces, and terminated with a newline.
- XThe \fB\-n\fP option eliminates the newline.
- X.IP
- XBy default, certain C escapes are translated.
- XThese include \eb, \ef, \en, \er, \et, \ev, and \e### (# is an octal digit).
- X\ec is equivalent to the \fB\-n\fP option.
- XThis expansion may be inhibitted with the \fB\-r\fP option,
- Xand may be re-enabled with the addition of the \fB\-e\fP option.
- X.IP "read [\fB\-ru\fIn\fR] \fIname ...\fP"
- XThe first variable name may be of the form \fIname\fB?\fIprompt\fR.
- X.IP "readonly [\fIname ...\fP]"
- X.IP "return [\fIstatus\fP]"
- X.ta 5n 10n 30n
- X.de O
- X.br
- X\t\\$1\t\\$2\t\\$3
- X..
- X.IP "set [\fB\(+-\fP\fI[a-z]\fP] [\fB\(+-o\fP \fIkeyword\fP] ..."
- XSet (\fB\-\fP) or clear (\fB+\fP) a shell option:
- X.O \-a allexport "all new variable are created with export attribute"
- X.O \-e errexit "exit on non-zero status [incorrect]"
- X.O "" bgnice "background jobs are run with lower priority"
- X.if \n(OE \{
- X.O "" emacs "BRL emacs-like line editing"\}
- X.O "" ignoreeof "shell will not exit of EOF, must use \fIexit\fP"
- X.O \-k keyword "variable assignments are recognized anywhere in command"
- X.O "" markdirs "[not implemented]"
- X.O \-m monitor "job control enabled (default for interactive shell)"
- X.O \-n noexec "compile input but do not execute (ignored if interactive)"
- X.O \-f noglob "don't expand filenames"
- X.O \-u nounset "dollar expansion of unset variables is an error"
- X.O \-v verbose "echo shell commands on stdout when compiling"
- X.O \-h trackall "add command pathnames to hash table"
- X.O "" vi "VI-like line editing"
- X.O \-x xtrace "echo simple commands while executing"
- X.IP "set [\fB\-\-\fP] \fIarg ...\fP"
- XSet shell arguments.
- X.IP "shift [\fInumber\fP]"
- X.IP "test"
- XSee the attached manual page.
- X.IP "times"
- X.IP "trap [\fIhandler\fP] [\fIsignal ...\fP]"
- X.IP "typeset [\fB\(+-irtx\fP] [\fIname\fP[\fB=\fIvalue\fR] ...]"
- XIf no arguments are given, lists all variables and their attributes.
- X.PP
- XIf options but no names are given, lists variables with specified
- Xattributes, and their values if unless ``+'' is used.
- X.PP
- XIf names are given, set the attributes of the named variables.
- XVariables may also be assigned a value.
- XIf used inside a function, the created variable are local to the function.
- X.PP
- XThe attributes are as follows.
- X.ta 5n 10n
- X\t\-i\tThe variable's value is stored as an integer.
- X.br
- X\t\-x\tThe variable is exported to the enviroment.
- X.br
- X\t\-r\tThe variable is read-only cannot be reassigned a value.
- X.br
- X\t\-t\tTrace (not implemented).
- X.br
- X\t\-f\tList functions instead of variable.
- X.\".IP "ulimit [\fB\-f\fP] [\fIvalue\fP]"
- X.ds OZ <OZ>
- X.IP "\fBulimit\fP \*(OK \fB\-\*(OZ\fP \*(CK \*(OK \fIn\fP \*(CK"
- X.RS
- X.TP "\w'\fB\-\-\ \ \ 'u"
- X.if \n(OB \{.B \-c
- XImpose a size limit of
- X.I n\^
- Xblocks on the size of core dumps.
- X.TP
- X.B \-d
- XImpose a size limit of
- X.I n\^
- Xblocks on the size of the data area.\}
- X.TP
- X.B \-f
- XImpose a size limit of
- X.I n
- Xblocks on files written by the shell
- Xand its child processes (files of any size may be read).
- X.if \n(OB \{.TP
- X.B \-m
- XImpose a soft limit of
- X.I n\^
- Xblocks on the size of physical memory.
- X.TP
- X.B \-t
- XImpose a time limit of
- X.I n\^
- Xseconds to be used by each process.\}
- X.PP
- XIf no option is given,
- X.B \-f
- Xis assumed.
- XIf
- X.I n
- Xis omitted, the current limit is printed.
- XAs far as
- X.B ulimit
- Xis concerned, a ``block'' is 512 bytes.
- X.PP
- XYou may lower your own resource limit,
- Xbut only a super-user (see
- X.IR su (1M))
- Xcan raise a limit.
- X.RE
- X.IP "umask [\fIvalue\fP]"
- X.IP "unalias \fIname ...\fP"
- XThe aliases for the given names are removed.
- X.IP "unset [\fB\-f\fP] \fIname ...\fP"
- X.IP "wait [\fIprocess-id\fP]"
- X.IP "whence [\fB\-v\fP] name ..."
- XFor each name, the type of command is listed.
- XThe \fB\-v\fP flag causes function and alias values to be listed.
- X.SS Job Control
- XJob control features are enabled by the
- X\fB\-m\fP or \fB\-o monitor\fP flags.
- XWhen job control is enabled, and the system supports job control,
- Xbackground commands and foreground commands that have been stopped
- X(usually by a
- X.SM SIGTSTP
- Xsignal generated by typing
- X.IR ^Z\^ )
- Xare placed into separate individual
- X.IR "process groups" .
- XThe following commands are used to manipulate these process groups:
- X.PP
- X.PD 0
- X.TP "\w'\fBkill\fP \*(OK \fIjob\fP \*(CK\ \ \ 'u"
- X\fBjobs\fP
- XDisplay information about the controlled jobs.
- XThe job number is given preceeded by a percent sign,
- Xfollowed by a plus sign if it is the ``current job'',
- Xor by a minus sign if it is the ``previous job'',
- Xthen the process group number for the job,
- Xthen the command.
- X.TP
- X\fBkill\fP [\fB\-\fIsignal\fR] \fIjob\fP ...
- XSend a signal (TERM by default) to the named job process group.
- X.TP
- X\fBfg\fP \*(OK \fIjob\fP \*(CK
- XResume the stopped foreground job in the foreground.
- XIf the process group
- X.I n
- Xis not specified then the ``current job'' is resumed.
- X.TP
- X\fBbg\fP \*(OK \fIjob\fP \*(CK
- XResume the stopped foreground job in the background.
- XIf the process group
- X.I n
- Xis not specified then the ``current job'' is resumed.
- X.PD
- X.PP
- XThe \fBfg\fP, \fBbg\fP, \fBkill\fP, and \fBwait\fP commands
- Xmay refer to jobs with the following ``percent'' sequences.
- XThe percent sign is optional with the fg and bg commands.
- X.PP
- X.PD 0
- X.TP "\w'\fBbg\fP \*(OK \fIn\fP \*(CK\ \ \ 'u"
- X.BR %+ ( %\- )
- XIf there is a ``current job'' (``previous job''),
- Xthen that job is selected.
- X.TP
- X.BI % n
- XIf the specified job number is one of the known jobs,
- Xthen that job is selected.
- X.TP
- X.BI % string
- XIf the string matches the initial part of a job's command,
- Xthen that job is selected.
- X.TP
- X.BI %? string
- XAs above, but the string may match any portion of the command.
- X.sp
- X.PP
- XIf the system does not support job control, monitor mode enables
- Xjob reporting. The jobs and kill commands
- Xfunctions as above, and you will
- Xbe informed when background jobs complete. Fg and bg are not
- Xavailiable.
- X.PD
- X.br
- X.SS "Interactive Input Line Editing"
- XWhen the
- X.B emacs
- Xoption is set,
- Xinteractive input line editing is enabled.
- XThis mode is slightly different from the emacs mode in AT&T's KornShell.
- XIn this mode various
- X.I "editing commands"
- X(typically bound to one or more control characters)
- Xcause immediate actions without waiting for a new-line.
- XSeveral
- X.I "editing commands"
- Xare bound to particular control characters
- Xwhen the shell is invoked;
- Xthese bindings can be changed using the following commands:
- X.br
- X.PP
- X.PD 0
- X.TP 2i
- X\fBbind\fP
- XThe current bindings are listed.
- X.TP
- X\fBbind\fP \*(OK \fIstring\fP \*(CK = \*(OK \fIediting-command\fP \*(CK
- XThe specified
- X.I "editing command\^"
- Xis bound to the given
- X.IR string ,
- Xwhich should consist of a control character
- X(which may be written using ``caret notation'' \fB^\fP\fIx\fP\|),
- Xoptionally preceded by one of the two prefix characters.
- XFuture input of the
- X.I string
- Xwill cause the
- X.I "editing command\^"
- Xto be immediately invoked.
- X.br
- XNote that although only two prefix characters (normal ESC and ^X)
- Xare supported, some multi-character sequences can be supported:
- X.br
- Xbind '^[['=prefix-2
- X.br
- Xbind '^XA'=up-history
- X.br
- Xbind '^XB'=down-history
- X.br
- Xbind '^XC'=forward-char
- X.br
- Xbind '^XC'=backward-char
- X.br
- Xwill bind the arrow keys on an ANSI terminal. Of course some escape
- Xsequences won't work out quite that nicely.
- X.TP
- X\fBbind -m\fP \*(OK \fIstring\fP \*(CK = \*(OK \fIsubstitute\fP \*(CK
- XThe specified input
- X.I string
- Xwill afterwards be immediately replaced by the given
- X.I substitute
- Xstring,
- Xwhich may contain
- X.IR "editing commands" .
- X.PD
- X.PP
- XThe following
- X.I "editing commands"
- Xare available;
- Xfirst the command name is given
- Xfollowed by its default binding (if any)
- Xusing caret notation
- X(note that the ASCII
- X.SM ESC
- Xcharacter is written as \s-1^[\s0\|),
- Xthen the editing function performed is decribed.
- XNote that
- X.I "editing command"
- Xnames are used only with the
- X.B bind
- Xcommand.
- XFurthermore,
- Xmany
- X.I "editing commands"
- Xare useful only on terminals with a visible cursor.
- XThe default bindings were chosen to resemble corresponding EMACS key bindings.
- XThe users tty characters (eg. erase) are bound to reasonable
- Xsubstitutes.
- X.br
- X.PP
- X.PD 0
- X.TP "\w'\fBdelete-word-backward\ \ ^[\|ERASE\fP\ \ \ 'u"
- X\fBabort\ \ ^G\fP
- XUseful as a response to a request for a
- X.B search-history
- Xpattern in order to abort the search.
- X.br
- X.TP
- X\fBauto-insert\fP
- XSimply causes the character to appear as literal input.
- X(Most ordinary characters are bound to this.)
- X.br
- X.TP
- X\fBbackward-char\ \ ^B\fP
- XMoves the cursor backward one character.
- X.br
- X.TP
- X\fBbackward-word\ \ ^[\|b\fP
- XMoves the cursor backward to the beginning of a word.
- X.br
- X.TP
- X\fBbeginning-of-line\ \ ^A\fP
- XMoves the cursor to the beginning of the input line
- X(after the prompt string).
- X.br
- X.TP
- X\fBcomplete\ \ ^[\|^[\fP
- XAutomatically completes as much as is unique of the hashed command name
- Xor the file name containing the cursor.
- XIf the entire remaining command or file name is unique
- Xa space is printed after its completion,
- Xunless it is a directory name in which case
- X.B /
- Xis postpended.
- XIf there is no hashed command or file name with the current partial word
- Xas its prefix,
- Xa bell character is output (usually causing a ``beep'').
- X.br
- X.TP
- X\fBcomplete-command\ \ ^X^[\fP
- XAutomatically completes as much as is unique of the hashed command name
- Xhaving the partial word up to the cursor as its prefix,
- Xas in the
- X.B complete
- Xcommand described above.
- XOnly command and function names seen since the last
- X.B "hash \-r"
- Xcommand are available for completion;
- Xthe
- X.B "hash"
- Xcommand may be used to register additional names.
- X.br
- X.TP
- X\fBcomplete-file\ \ ^[\|^X\fP
- XAutomatically completes as much as is unique of the file name
- Xhaving the partial word up to the cursor as its prefix,
- Xas in the
- X.B complete
- Xcommand described above.
- X.br
- X.TP
- X\fBcopy-last-arg\ \ ^[\|_\fP
- XThe last word of the previous command is inserted at the
- Xcursor. Note I/O redirections do not count as words of
- Xthe command.
- X.br
- X.TP
- X\fBdelete-char-backward\ \ ERASE\fP
- XDeletes the character before the cursor.
- X.br
- X.TP
- X\fBdelete-char-forward\fP
- XDeletes the character after the cursor.
- X.br
- X.TP
- X\fBdelete-word-backward\ \ ^[\|ERASE\fP
- XDeletes characters before the cursor back to the beginning of a word.
- X.br
- X.TP
- X\fBdelete-word-forward\ \ ^[\|d\fP
- XDeletes characters after the cursor up to the end of a word.
- X.br
- X.TP
- X\fBdown-history\ \ ^N\fP
- XScrolls the history buffer forward one line (later).
- XEach input line originally starts just after
- Xthe last entry in the history buffer,
- Xso
- X.B down-history
- Xis not useful until either
- X.B search-history
- Xor
- X.B up-history
- Xhas been performed.
- X.br
- X.TP
- X\fBend-of-line\ \ ^E\fP
- XMoves the cursor to the end of the input line.
- X.br
- X.TP
- X\fBeot\ \ ^_\fP
- XActs as an end-of-file;
- Xthis is useful because edit-mode input
- Xdisables normal terminal input canonicalization.
- X.br
- X.TP
- X\fBeot-or-delete\ \ ^D\fP
- XActs as eot if alone on a line;
- Xotherwise acts as delete-char-forward.
- X.br
- X.TP
- X\fBexchange-point-and-mark\ \ ^X\|^X\fP
- XPlaces the cursor where the mark is, and sets the
- Xmark to where the cursor was.
- X.br
- X.TP
- X\fBforward-char\ \ ^F\fP
- XMoves the cursor forward one position.
- X.br
- X.TP
- X\fBforward-word\ \ ^[\|f\fP
- XMoves the cursor forward to the end of a word.
- X.br
- X.TP
- X\fBkill-line\ \ KILL\fP
- XDeletes the entire input line.
- X.br
- X.TP
- X\fBkill-to-eol\ \ ^K\fP
- XDeletes the input from the cursor to the end of the line.
- X.br
- X.TP
- X\fBkill-region\ \ ^W\fP
- XDeletes the input between the cursor and the mark.
- X.br
- X.TP
- X\fBlist\ \ ^[\|?\fP
- XPrints a sorted, columnated list of hashed command names or file names
- X(if any) that can complete the partial word containing the cursor.
- XDirectory names have
- X.B /
- Xpostpended to them,
- Xand executable file names are followed by
- X.BR \(** .
- X.br
- X.TP
- X\fBlist-command\ \ ^X\|?\fP
- XPrints a sorted, columnated list of hashed command names
- X(if any) that can complete the partial word containing the cursor.
- X.br
- X.TP
- X\fBlist-file\fP
- XPrints a sorted, columnated list of file names
- X(if any) that can complete the partial word containing the cursor.
- XFile type indicators are postpended as described under
- X.B list
- Xabove.
- X.br
- X.TP
- X\fBnewline\ \ ^J\ \fP\fIand\^\fP\fB\ ^M\fP
- XCauses the current input line to be processed by the shell.
- X(The current cursor position may be anywhere on the line.)
- X.br
- X.TP
- X\fBnewline-and-next\ \ ^O\fP
- XCauses the current input line to be processed by the shell, and
- Xthe next line from history becomes the current line. This is
- Xonly useful after an up-history or search-history.
- X.br
- X.TP
- X\fBno-op\ \ QUIT\fP
- XDoes nothing.
- X.br
- X.TP
- X\fBprefix-1\ \ ^[\fP
- XIntroduces a 2-character command sequence.
- X.br
- X.TP
- X\fBprefix-2\ \ ^X\fP
- XIntroduces a 2-character command sequence.
- X.br
- X.TP
- X\fBquote\ \ ^^\fP
- XThe following character is taken literally
- Xrather than as an
- X.IR "editing command" .
- X.br
- X.TP
- X\fBredraw\ \ ^L\fP
- XReprints the prompt string and the current input line.
- X.br
- X.TP
- X\fBsearch-character\ \ ^]\fP
- XSearch forward in the current line for the next keyboard character.
- X.br
- X.TP
- X\fBsearch-history\ \ ^R\fP
- XEnter incremental search mode.
- XThe internal history list is searched backwards for commands matching the input.
- XAn initial ``^'' in the search string anchors the search.
- XThe escape key will leave search mode.
- XOther commands will be executed after leaving search mode (unless
- Xof course they are prefixed by escape, in which case they will
- Xalmost certainly do the wrong thing).
- XSuccessive
- X.B search-history
- Xcommands continue searching backward
- Xto the next previous occurrence of the pattern.
- XThe history buffer retains only a finite number of lines;
- Xthe oldest are discarded as necessary.
- X.br
- X.TP
- X\fBset-mark-command\ \ ^]\|<space>\fP
- XSearch forward in the current line for the next keyboard character.
- X.br
- X.ie \n(OX \{.TP
- X\fBstuff\ \ ^T\fP\}
- X.el \{.TP
- X\fBstuff\fP\}
- XOn systems supporting it,
- Xpushes the bound character back onto the terminal input
- Xwhere it may receive special processing by the terminal handler.
- X.if \n(OX \{This is useful for the BRL
- X.B ^T
- X``mini-systat'' feature,
- Xfor example.\}
- X.br
- X.TP
- X\fBstuff-reset\fP
- XActs like
- X.BR stuff\^ ,
- Xthen aborts input the same as an interrupt.
- X.br
- X.ie \n(OX \{.TP
- X\fBtranspose-chars\fP\}
- X.el \{.TP
- X\fBtranspose-chars\ \ ^T\fP\}
- XExchanges the two characters on either side of the cursor, or
- Xthe two previous characters if the cursor is at end of line.
- X.br
- X.TP
- X\fBup-history\ \ ^P\fP
- XScrolls the history buffer backward one line (earlier).
- X.br
- X.TP
- X\fByank\ \ ^Y\fP
- XInserts the most recently killed text string at the current cursor position.
- X.br
- X.TP
- X\fByank-pop\ \ ^[\|y\fP
- XImmediately after a
- X.BR yank ,
- Xreplaces the inserted text string with the
- Xnext previous killed text string.
- X.PD
- X.br
- X.SH FILES
- X~/.profile
- X.br
- X/etc/profile
- X.SH SEE ALSO
- XSh(1) on System V or Sun OS.
- X.LP
- X.I "UNIX Shell Programming,"
- XStephan G. Kochan,
- XPatrick H. Wood,
- XHayden.
- X.LP
- X.I "KornShell: Command and Programming Language (not yet published),"
- XMorris Bolsky and David Korn.
- X.SH AUTHORS
- XBased on the public domain 7th edition Bourne shell.
- X.LP
- XSystem V and Korn modifications by Eric Gisin,
- Xwith contributions by
- XRon Natalie, Arnold Robbins, Doug Gwyn, Erik Baalbergen, AT&T (getopt(3)).
- X.SH DIFFERENCES FROM AT&T VERSION
- XVi editing mode is not implemented.
- XThe \fBselect\fP statement is not implemented.
- XVariable arrays are not implemented.
- XVariable attributes other than integer are not implemented.
- XThe \fBERR\fP and \fBEXIT\fP traps are not implemented for functions.
- XAlias expansion is inhibited at the beginning of an alias definition
- Xin the AT&T version.
- XKorn evaluates expressions differently [elaborate].
- X.SH BUGS
- XInteractive shells will occasionally hang while waiting for a job
- Xin the BSD version.
- X.LP
- XThe 8th bit is stripped in emacs mode.
- X.LP
- XQuoting double-quote (") characters inside back-quote (`) inside
- Xdouble-quotes does not behave properly. Why are you doing this?
- X.LP
- XJob control on System V is not really job control. In fact it is
- Xnot much of anything.
- X.LP
- XThe emacs mode can ``lose'' stty command done by the user.
- X.LP
- XUnsetting special variables
- Xmay cause unexpected results.
- X.LP
- XFunctions declared as having local scope really have global scope.
- X.LP
- XHere documents inside functions do not work correctly.
- X.LP
- XExit on error (\fBset \-e\fP or \fBset -o errexit\fP) does not work
- Xcorrectly.
- X.TH TEST 1 "January 1988" "Korn shell"
- X.ta 30n
- X.de X
- X.br
- X\\$1\t\\$2
- X..
- X.SH NAME
- Xtest \- test condition (Korn and 8th edition)
- X.SH SYNOPSIS
- X\fBtest\fP \fIexpression\fP
- X.br
- X\fB[\fP \fIexpression\fP \fB]\fP
- X.SH DESCRIPTION
- X\fBTest\f evalutates the \fIexpression\fP and returns zero status if true,
- Xand non-zero status otherwise.
- XIt is normally used as the controlling command of the \fBif\fP and \fBwhile\fP statements.
- X.LP
- XThe following basic expressions are available.
- X.IP
- X.X "-r file" "file exists and is readable"
- X.X "-w file" "file exists and is writable"
- X.X "-x file" "file exists and is executable"
- X.X "-f file" "file is a regular file"
- X.X "-d file" "file is a directory"
- X.X "-c file" "file is a character special device"
- X.X "-b file" "file is a block special device"
- X.X "-p file" "file is a named pipe"
- X.X "-u file" "file mode has setuid bit"
- X.X "-g file" "file mode has setgid bit"
- X.X "-k file" "file mode has sticky bit"
- X.X "-s file" "file is not empty"
- X.X "-L file" "file is a symbolic link"
- X.X "-S file" "file is a socket"
- X.X "file -nt file" "first file is newer than second file"
- X.X "file -ot file" "first file is older than second file"
- X.X "file -ef file" "first file is the same file as second file"
- X.X "-t filedes" "file descriptor is a tty device"
- X.IP
- X.X "string" "string is not null"
- X.X "-z string" "string is null"
- X.X "-n string" "string is not null"
- X.X "string = string" "strings are equal"
- X.X "string != string" "strings are not equal"
- X.IP
- X.X "number -eq number" "numbers compare equal"
- X.X "number -ne number" "numbers compare not equal"
- X.X "number -ge number" "numbers compare greater than or equal"
- X.X "number -gt number" "numbers compare greater than"
- X.X "number -le number" "numbers compare less than or equal"
- X.X "number -lt number" "numbers compare less than"
- X.LP
- XThe above basic expressions may be combined with the following operators.
- X.IP
- X.X "expr -o expr" "logical or"
- X.X "expr -a expr" "logical and"
- X.X "! expr" "logical not"
- X.X "( expr )" "grouping"
- X.SH AUTHOR
- XErik Baalbergen. Modified by Arnold Robbins.
- X.rn LP P
- X.TH GETOPTS 1 "January 1988" "Korn shell"
- X.SH NAME
- Xgetopts \- parse command options
- X.SH SYNOPSIS
- X.B getopts
- Xoptstring name [arg ...]
- X.SH DESCRIPTION
- X.I getopts
- Xis used by shell procedures
- Xto parse positional parameters and to check for legal options.
- XIt supports all applicable rules of the command syntax standard
- X(see Rules 3-10,
- X.IR intro (1)).
- XIt should be used in place of the
- X.IR getopt (1)
- Xcommand.
- X(See the
- X.BR \s-1WARNING\s0 ,
- Xbelow.)
- X.PP
- X.I optstring
- Xmust contain the option letters the command using
- X.I getopts
- Xwill recognize;
- Xif a letter is followed by a colon,
- Xthe option is expected to have an argument
- Xwhich should be separated from it by white space.
- X.PP
- XEach time it is invoked,
- X.I getopts
- Xwill place the next option in the shell variable
- X.I name
- Xand the index of the next argument to be processed in the shell variable
- X.BR \s-1OPTIND\s0 .
- XWhenever the shell or a shell procedure is invoked,
- X.B \s-1OPTIND\s0
- Xis initialized to
- X.BR 1 .
- X.PP
- XWhen an option requires an option-argument,
- X.I getopts
- Xplaces it in the shell variable
- X.BR \s-1OPTARG\s0 .
- X.P
- XIf an illegal option is encountered,
- X.B ?\&
- Xwill be placed in
- X.IR name .
- X.P
- XWhen the end of the options is encountered,
- X.I getopts
- Xexits with a non-zero exit status.
- XThe special option
- X.RB `` \-\- ''
- Xmay be used to delimit the end of the options.
- X.P
- XBy default,
- X.I getopts
- Xparses the positional parameters.
- XIf extra arguments
- X.RI ( arg
- X\&...) are given on the
- X.I getopts
- Xcommand line,
- X.I getopts
- Xwill parse them instead.
- X.PP
- XSo all new commands will adhere to the command syntax standard described in
- X.IR intro (1),
- Xthey should use
- X.IR getopts (1)
- Xor
- X.IR getopt (3C)
- Xto parse positional parameters
- Xand check for options that are legal for that command
- X(see
- X.BR \s-1WARNINGS\s0 ,
- Xbelow).
- X.SH EXAMPLE
- XThe following fragment of a shell program
- Xshows how one might process the arguments
- Xfor a command that can take the options
- X.B a
- Xor
- X.BR b ,
- Xas well as the option
- X.BR o ,
- Xwhich requires an option-argument:
- X.PP
- X.RS
- X.nf
- X.ss 18
- X.ta +.5i +1i
- X\fBwhile getopts abo: c
- Xdo
- X case $c in
- X a\(bvb) FLAGS=$FLAGS$c;;
- X o) OARG=$OPTARG;;
- X \e?) echo $USAGE 1>&2
- X exit 2;;
- X esac
- Xdone
- Xshift OPTIND\-1\fP
- X.fi
- X.ta
- X.ss 12
- X.RE
- X.PP
- XThis code will accept any of the following as equivalent:
- X.PP
- X.RS
- X.nf
- X.ss 18
- X\fBcmd \-a \-b \-o "xxx z yy" file
- Xcmd \-a \-b \-o "xxx z yy" \-\- file
- Xcmd \-ab \-o "xxx z yy" file
- Xcmd \-ab \-o "xxx z yy" \-\- file\fP
- X.fi
- X.ss 12
- X.RE
- X.SH SEE ALSO
- Xintro(1),
- Xsh(1).
- X.br
- Xgetopt(3C)
- Xin the
- X.IR "Programmer's Reference Manual" .
- X.br
- X.IR "UNIX System V Release 3.0 Release Notes" .
- X.SH WARNING
- XAlthough the following command syntax rule (see
- X.IR intro (1))
- Xrelaxations are permitted under the current implementation,
- Xthey should not be used because they may not be supported
- Xin future releases of the system.
- XAs in the
- X.B \s-1EXAMPLE\s0
- Xsection above,
- X.B a
- Xand
- X.B b
- Xare options,
- Xand the option
- X.B o
- Xrequires an option-argument:
- X.PP
- X.RS
- X.nf
- X.ta +1i +1.5i
- X\fBcmd \-aboxxx file\fP (Rule 5 violation: options with
- X option-arguments must not be grouped with other options)
- X\fBcmd \-ab \-oxxx file\fP (Rule 6 violation: there must be
- X white space after an option that takes an option-argument)
- X.fi
- X.ta
- X.RE
- X.PP
- XChanging the value of the shell variable
- X.B \s-1OPTIND\s0
- Xor parsing different sets of arguments
- Xmay lead to unexpected results.
- X.SH DIAGNOSTICS
- X.I getopts
- Xprints an error message on the standard error output
- Xwhen it encounters an option letter not included in
- X.IR optstring .
- END_OF_FILE
- if test 31646 -ne `wc -c <'ksh.1'`; then
- echo shar: \"'ksh.1'\" unpacked with wrong size!
- fi
- # end of 'ksh.1'
- fi
- if test -f 'sh/jobs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sh/jobs.c'\"
- else
- echo shar: Extracting \"'sh/jobs.c'\" \(16759 characters\)
- sed "s/^X//" >'sh/jobs.c' <<'END_OF_FILE'
- X/*
- X * Process and job control
- X */
- X#ifndef lint
- Xstatic char *RCSid = "$Id: jobs.c,v 3.5 89/03/27 15:51:01 egisin Exp $";
- Xstatic char sccs_id[] = "@(#)jobs.c 1.4 91/08/16 17:36:59 (sjg)";
- X#endif
- X
- X/*
- X * based on version by Ron Natalie, BRL
- X * modified by Simon J. Gerraty <sjg@melb.bull.oz.au>
- X *
- X * TODO:
- X * change Proc table to Job table, with array of pids.
- X * make %+ be jobs, %- be jobs->next.
- X * do not JFREE members of pipeline.
- X * consider procs[] related critical sections.
- X * signal(SIGCHLD, j_sigchld) should be
- X * sigaction(SIGCHLD, sigchld, NULL),
- X * with sigchld.sa_flags = SA_RESTART.
- X * There is a simple work-around if there is no SA_RESTART.
- X */
- X
- X#include <stddef.h>
- X#include <string.h>
- X#include <stdio.h>
- X#include <errno.h>
- X#include <unistd.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X#include <sys/types.h>
- X#include <sys/times.h>
- X#include <sys/wait.h>
- X#include "sh.h"
- X#include "tree.h"
- X#ifdef JOBS
- X#ifdef _BSD
- X#include <sys/ioctl.h>
- X#else
- X#include "termios.h"
- X#endif
- X#endif
- X
- X#ifndef WIFCORED
- X#define WIFCORED(x) (!!((x)&0x80)) /* non-standard */
- X#endif
- X
- X/* as of P1003.1 Draft 12.3:
- X * pid_t getpgrp(void); // Get process group id
- X * pid_t setsid(void); // Create session and Set process group id
- X * int setpgid(pid_t pid, pid_t pgid); // Set process group id for job control
- X */
- X
- Xstatic int sigchld_caught; /* for recording child terminations */
- X
- X#ifdef JOBS
- X#ifdef _BSD /* _BSD 4.* */
- X#define setpgid(p, pg) setpgrp(p, pg)
- X#define getpgid(p) getpgrp(p)
- X#define tcsetpgrp(fd,p) ioctl(fd, TIOCSPGRP, &(p))
- X#else /* POSIX-compatible */
- X#define getpgid(p) getpgrp() /* 1003.1 stupidity */
- X#define killpg(p, s) kill(-(p), s)
- X#endif
- X#endif
- X
- X#ifndef SIGCHLD
- X#define SIGCHLD SIGCLD
- X#endif
- X
- Xtypedef struct Proc Proc;
- Xstruct Proc {
- X Proc *next; /* `procs' list link */
- X int job; /* job number: %n */
- X short Volatile state; /* proc state */
- X short Volatile notify; /* proc state has changed */
- X Proc *prev; /* prev member of pipeline */
- X pid_t proc; /* process id */
- X pid_t pgrp; /* process group if flag[FMONITOR] */
- X short flags; /* execute flags */
- X int status; /* wait status */
- X clock_t utime, stime; /* user/system time when JDONE */
- X char com [48]; /* command */
- X};
- X
- X/* proc states */
- X#define JFREE 0 /* unused proc */
- X#define JRUN 1 /* foreground */
- X#define JEXIT 2 /* exit termination */
- X#define JSIGNAL 3 /* signal termination */
- X#define JSTOP 4 /* stopped */
- X
- Xstatic Proc *procs = NULL; /* job/process table */
- X
- Xclock_t j_utime, j_stime; /* user and system time for last job a-waited */
- X#ifdef JOBS
- Xstatic int sm_default, sm_sigchld; /* signal masks */
- Xstatic int our_pgrp; /* shell's pgrp */
- X#endif
- Xstatic Proc *j_lastj; /* last proc created by exchild */
- Xstatic int j_lastjob = 0; /* last created job */
- Xstatic int j_current = 0; /* current job */
- Xstatic int j_previous = 0; /* previous job */
- X
- Xstatic int j_newjob ARGS((void));
- Xstatic void j_print ARGS((Proc *j));
- Xstatic Proc *j_search ARGS((int job));
- Xstatic int j_waitj ARGS((Proc *j, int intr));
- Xstatic void j_sigchld ARGS((int sig));
- X
- X/* initialize job control */
- Xvoid
- Xj_init()
- X{
- X#ifdef JOBS
- X#ifdef NTTYDISC
- X int ldisc = NTTYDISC; /* BSD brain damage */
- X
- X if (ttyfd >= 0)
- X ioctl(ttyfd, TIOCSETD, &ldisc);
- X#endif
- X our_pgrp = getpgid(0);
- X sigchld_caught = 0;
- X sm_default = 0;
- X sm_sigchld = sigmask(SIGCHLD);
- X _TRACE(5, ("j_init: sm_sigchld == 0x%x", sm_sigchld));
- X#endif
- X#if defined(_SYSV) && !defined(JOBS)
- X signal(SIGCHLD, SIG_DFL); /* necessary ??? */
- X#endif
- X}
- X
- X/* job cleanup before shell exit */
- Xvoid
- Xj_exit()
- X{
- X register Proc *j;
- X int killed = 0;
- X
- X#ifdef JOBS
- X /* kill stopped jobs */
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state == JSTOP) {
- X killed ++;
- X killpg(j->pgrp, SIGHUP);
- X killpg(j->pgrp, SIGCONT);
- X }
- X if (killed)
- X sleep(1);
- X#endif
- X j_notify();
- X
- X#ifdef JOBS
- X if (flag[FMONITOR]) {
- X flag[FMONITOR] = 0;
- X j_change();
- X }
- X#endif
- X}
- X
- X#ifdef JOBS
- X/* turn job control on or off according to flag[FMONITOR] */
- Xvoid
- Xj_change()
- X{
- X static handler_t old_tstp, old_ttin, old_ttou;
- X
- X if (flag[FMONITOR]) {
- X if (ttyfd < 0) {
- X flag[FMONITOR] = 0;
- X shellf("job control requires tty\n");
- X return;
- X }
- X (void) signal(SIGCHLD, j_sigchld);
- X sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
- X old_tstp = signal(SIGTSTP, SIG_IGN);
- X sigtraps[SIGTSTP].sig_dfl = 1;
- X old_ttin = signal(SIGTTIN, SIG_IGN);
- X sigtraps[SIGTTIN].sig_dfl = 1;
- X old_ttou = signal(SIGTTOU, SIG_IGN);
- X sigtraps[SIGTTOU].sig_dfl = 1;
- X sigsetmask(sm_default);
- X tcsetpgrp(ttyfd, our_pgrp);
- X } else {
- X (void) signal(SIGCHLD, SIG_DFL);
- X (void) signal(SIGTSTP, old_tstp);
- X sigtraps[SIGTSTP].sig_dfl = 0;
- X (void) signal(SIGTTIN, old_ttin);
- X sigtraps[SIGTTIN].sig_dfl = 0;
- X (void) signal(SIGTTOU, old_ttou);
- X sigtraps[SIGTTOU].sig_dfl = 0;
- X }
- X}
- X#endif
- X
- X/* execute tree in child subprocess */
- Xint
- Xexchild(t, flags)
- X struct op *t;
- X int flags;
- X{
- X register int i;
- X register Proc *j;
- X int rv = 0;
- X int forksleep;
- X
- X flags &= ~XFORK;
- X if ((flags&XEXEC))
- X return execute(t, flags);
- X
- X /* get free Proc entry */
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state == JFREE)
- X goto Found;
- X j = (Proc*) alloc(sizeof(Proc), APERM);
- X j->next = procs;
- X j->state = JFREE;
- X procs = j;
- X Found:
- X
- X j->prev = ((flags&XPIPEI)) ? j_lastj : NULL;
- X j->proc = j->pgrp = 0;
- X j->flags = flags;
- X j->job = (flags&XPIPEI) ? j_lastjob : j_newjob();
- X snptreef(j->com, sizeof(j->com), "%T", t); /* save proc's command */
- X j->com[sizeof(j->com)-1] = '\0';
- X j->state = JRUN;
- X
- X /* stdio buffer must be flushed and invalidated */
- X for (i = 0; i < NUFILE; i++)
- X flushshf(i);
- X
- X /* create child process */
- X forksleep = 0;
- X while ((i = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
- X if (forksleep) {
- X sleep(forksleep);
- X forksleep <<= 1;
- X } else
- X forksleep = 1;
- X }
- X if (i < 0) {
- X j->state = JFREE;
- X errorf("cannot fork - try again\n");
- X }
- X j->proc = (i != 0) ? i : getpid();
- X
- X#ifdef JOBS
- X /* job control set up */
- X if (flag[FMONITOR] && !(flags&XXCOM)) {
- X j->pgrp = !(flags&XPIPEI) ? j->proc : j_lastj->pgrp;
- X /* do in both parent and child to avoid fork race condition */
- X if (!(flags&XBGND))
- X tcsetpgrp(ttyfd, j->pgrp); /* could be trouble */
- X setpgid(j->proc, j->pgrp);
- X }
- X#endif
- X j_lastj = j;
- X
- X if (i == 0) { /* child */
- X e.oenv = NULL;
- X if (flag[FTALKING])
- X restoresigs();
- X if ((flags&XBGND) && !flag[FMONITOR]) {
- X signal(SIGINT, SIG_IGN);
- X signal(SIGQUIT, SIG_IGN);
- X if (flag[FTALKING])
- X signal(SIGTERM, SIG_DFL);
- X if (!(flags&XPIPEI)) {
- X i = open("/dev/null", 0);
- X (void) dup2(i, 0);
- X close(i);
- X }
- X }
- X for (j = procs; j != NULL; j = j->next)
- X j->state = JFREE;
- X ttyfd = -1;
- X flag[FMONITOR] = flag[FTALKING] = 0;
- X cleartraps();
- X execute(t, flags|XEXEC); /* no return */
- X /* NOTREACHED */
- X }
- X
- X /* shell (parent) stuff */
- X if ((flags&XBGND)) { /* async statement */
- X async = j->proc;
- X j_previous = j_current;
- X j_current = j->job;
- X if (flag[FTALKING])
- X j_print(j);
- X } else { /* sync statement */
- X if (!(flags&XPIPE))
- X rv = j_waitj(j, 0);
- X }
- X
- X return rv;
- X}
- X
- X/* wait for last job: pipeline or $() sub-process */
- Xint
- Xwaitlast()
- X{
- X return j_waitj(j_lastj, 0);
- X}
- X
- X/* wait for job to complete or change state */
- Xstatic int
- Xj_waitj(aj, intr)
- X Proc *aj;
- X int intr; /* interruptable */
- X{
- X register Proc *j;
- X int rv = 1;
- X int ttysig = 0;
- X
- X#ifdef JOBS
- X if (flag[FMONITOR])
- X {
- X _TRACE(5, ("j_waitj: sigsetmask(sm_sigchld==0x%x)", sm_sigchld));
- X sigsetmask(sm_sigchld);
- X }
- X#endif
- X /* wait for all members of pipeline */
- X for (j = aj; j != NULL; j = j->prev) {
- X /* wait for job to finish, stop, or ^C of built-in wait */
- X while (j->state == JRUN) {
- X#ifdef JOBS
- X if (flag[FMONITOR])
- X {
- X /*
- X * 91-07-07 <sjg@sun0>
- X * we don't want to wait for a signal
- X * that has already arrived :-)
- X */
- X if (!sigchld_caught)
- X {
- X _TRACE(4, ("j_waitj: sigpause(%d), sigchld_caught==%d", sm_default, sigchld_caught));
- X sigpause(sm_default);
- X _TRACE(4, ("j_waitj: sigpause() returned %d, sigchld_caught==%d", errno, sigchld_caught));
- X }
- X }
- X else
- X#endif
- X j_sigchld(0);
- X /*
- X * Children to reap
- X */
- X if (sigchld_caught)
- X j_reapchld();
- X _TRACE(4, ("j_waitj: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
- X
- X if (sigtraps[SIGINT].set && intr)
- X goto Break;
- X }
- X if (j->state == JEXIT) { /* exit termination */
- X if (!(j->flags&XPIPEO))
- X rv = WEXITSTATUS(j->status);
- X j->notify = 0;
- X } else
- X if (j->state == JSIGNAL) { /* signalled to death */
- X if (!(j->flags&XPIPEO))
- X rv = 0x80 + WTERMSIG(j->status);
- X if (WTERMSIG(j->status) == SIGINT ||
- X WTERMSIG(j->status) == SIGPIPE && (j->flags&XPIPEO))
- X j->notify = 0;
- X if (WTERMSIG(j->status) == SIGINT ||
- X WTERMSIG(j->status) == SIGQUIT)
- X ttysig = 1;
- X } else
- X#ifdef JOBS
- X if (j->state == JSTOP)
- X if (WSTOPSIG(j->status) == SIGTSTP)
- X ttysig = 1;
- X#else
- X ;
- X#endif
- X }
- X
- X /* compute total child time for time statement */
- X for (j = aj; j != NULL; j = j->prev)
- X j_utime += j->utime, j_stime += j->stime;
- X
- X /* find new current job */
- X#ifdef JOBS
- X if (aj->state == JSTOP) {
- X j_previous = j_current;
- X j_current = aj->job;
- X } else {
- X#else
- X if (1) {
- X#endif
- X int hijob = 0;
- X
- X /* todo: this needs to be done in j_notify */
- X /* todo: figure out what to do with j_previous */
- X j_current = 0;
- X for (j = procs; j != NULL; j = j->next)
- X if ((j->state == JRUN || j->state == JSTOP)
- X && j->job > hijob) {
- X hijob = j->job;
- X j_current = j->job;
- X }
- X }
- X
- X Break:
- X#ifdef JOBS
- X if (flag[FMONITOR]) {
- X /* reset shell job control state */
- X sigsetmask(sm_default);
- X tcsetpgrp(ttyfd, our_pgrp);
- X }
- X#endif
- X if (ttysig)
- X fputc('\n', shlout);
- X j_notify();
- X
- X return rv;
- X}
- X
- X/* SIGCHLD handler to reap children */
- X/*
- X * 91-07-07 <sjg@sun0>
- X * On the Sun SS2 this appears to get called
- X * too quickly!
- X * So just record the event and process later.
- X */
- Xstatic void
- Xj_sigchld(sig)
- X int sig;
- X{
- X sigchld_caught++; /* acknowledge it */
- X#if defined(_SYSV) && !defined(JOBS)
- X /* non-zero sig means called as handler */
- X /* 5.2 handlers must reinstate themselves */
- X if (sig) signal(SIGCHLD, j_sigchld);
- X#endif
- X}
- X
- X/*
- X * 91-07-07 <sjg@sun0>
- X * This now gets called when j_sigchld()
- X * has recorded some signals...
- X */
- Xj_reapchld()
- X{
- X struct tms t0, t1;
- X#ifdef JOBS
- X int sm_old;
- X
- X sm_old = sigblock(0); /* just get current mask */
- X#endif
- X _TRACE(5, ("j_reapchld: sm_old==0x%x, sigchld_caught==%d", sm_old, sigchld_caught));
- X (void) times(&t0);
- X
- X do {
- X register Proc *j;
- X int pid, status;
- X#ifdef JOBS
- X if (flag[FMONITOR])
- X pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
- X else
- X#endif
- X pid = wait(&status);
- X if (pid <= 0) /* return if would block (0) ... */
- X break; /* ... or no children or interrupted (-1) */
- X (void) times(&t1);
- X
- X _TRACE(5, ("j_reapchld: looking for pid==%d", pid));
- X
- X for (j = procs; j != NULL; j = j->next)
- X {
- X _TRACE(6, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
- X if (j->state != JFREE && j->proc == pid)
- X goto Found;
- X }
- X _TRACE(5, ("j_reapchld: did not find pid==%d", pid));
- X continue;
- X Found:
- X _TRACE(5, ("j_reapchld: found pid==%d", pid));
- X j->notify = 1;
- X j->status = status;
- X#ifdef JOBS
- X if (WIFSTOPPED(status))
- X j->state = JSTOP;
- X else
- X#endif
- X if (WIFEXITED(status))
- X j->state = JEXIT;
- X else
- X if (WIFSIGNALED(status))
- X j->state = JSIGNAL;
- X
- X /* compute child's time */
- X /* todo: what does a stopped job do? */
- X j->utime = t1.tms_cutime - t0.tms_cutime;
- X j->stime = t1.tms_cstime - t0.tms_cstime;
- X t0 = t1;
- X#ifdef JOBS
- X sigblock(sm_sigchld);
- X#endif
- X if (--sigchld_caught < 0) /* reduce the count */
- X sigchld_caught = 0;
- X#ifdef JOBS
- X _TRACE(5, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
- X sigsetmask(sm_old); /* restore old mask */
- X#endif
- X#ifdef JOBS
- X } while (flag[FMONITOR]);
- X#else
- X } while (0); /* only once if wait()ing */
- X#endif
- X}
- X
- Xj_reap()
- X{
- X if (sigchld_caught)
- X j_reapchld();
- X#if defined(_SYSV) && !defined(JOBS)
- X signal(SIGCHLD, j_sigchld);
- X signal(SIGCLD, SIG_DFL);
- X#endif
- X return(0);
- X}
- X
- X/* wait for child, interruptable */
- Xint
- Xwaitfor(job)
- X int job;
- X{
- X register Proc *j;
- X
- X if (job == 0 && j_current == 0)
- X errorf("no current job\n");
- X j = j_search((job == 0) ? j_current : job);
- X if (j == NULL)
- X errorf("no such job: %d\n", job);
- X if (flag[FTALKING])
- X j_print(j);
- X if (e.interactive) { /* flush stdout, shlout */
- X fflush(shf[1]);
- X fflush(shf[2]);
- X }
- X return j_waitj(j, 1);
- X}
- X
- X/* kill (built-in) a job */
- Xvoid
- Xj_kill(job, sig)
- X int job;
- X int sig;
- X{
- X register Proc *j;
- X
- X j = j_search(job);
- X if (j == NULL)
- X errorf("cannot find job\n");
- X if (j->pgrp == 0) { /* !flag[FMONITOR] */
- X if (kill(j->proc, sig) < 0) /* todo: all member of pipeline */
- X errorf("kill: %s\n", strerror(errno));
- X#ifdef JOBS
- X } else {
- X if (sig == SIGTERM || sig == SIGHUP)
- X (void) killpg(j->pgrp, SIGCONT);
- X if (killpg(j->pgrp, sig) < 0)
- X errorf("killpg: %s\n", strerror(errno));
- X#endif
- X }
- X}
- X
- X#ifdef JOBS
- X
- X/* fg and bg built-ins */
- Xint
- Xj_resume(job, bg)
- X int job;
- X int bg;
- X{
- X register Proc *j;
- X
- X j = j_search((job == 0) ? j_current : job);
- X if (j == NULL)
- X errorf("cannot find job\n", job);
- X if (j->pgrp == 0)
- X errorf("job not job-controlled\n");
- X
- X j->state = JRUN;
- X j_print(j);
- X flushshf(2);
- X
- X if (!bg)
- X tcsetpgrp(ttyfd, j->pgrp); /* attach shell to job */
- X if (killpg(j->pgrp, SIGCONT) < 0)
- X errorf("cannot continue job %%%d\n", job);
- X if (!bg)
- X return j_waitj(j, 0);
- X return 0;
- X}
- X
- X#endif
- X
- X/* list jobs for jobs built-in */
- Xvoid
- Xj_jobs()
- X{
- X register Proc *j;
- X
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state != JFREE)
- X j_print(j);
- X}
- X
- X/* list jobs for top-level notification */
- Xvoid
- Xj_notify()
- X{
- X register Proc *j;
- X
- X /*
- X * since reaping is no longer done in the signal handler
- X * we had better try here...
- X */
- X if (sigchld_caught)
- X j_reapchld();
- X
- X for (j = procs; j != NULL; j = j->next) {
- X if (j->state == JEXIT && !flag[FTALKING])
- X j->notify = 0;
- X if (j->state != JFREE && j->notify)
- X j_print(j);
- X if (j->state == JEXIT || j->state == JSIGNAL)
- X j->state = JFREE;
- X j->notify = 0;
- X }
- X}
- X
- Xstatic void
- Xj_print(j)
- X register Proc *j;
- X{
- X char buf [64], *s = buf;
- X
- X switch (j->state) {
- X case JRUN:
- X s = "Running";
- X break;
- X
- X#ifdef JOBS
- X case JSTOP:
- X strcpy(buf, "Stopped ");
- X s = strchr(sigtraps[WSTOPSIG(j->status)].mess, '(');
- X if (s != NULL)
- X strcat(buf, s);
- X s = buf;
- X break;
- X#endif
- X
- X case JEXIT: {
- X int rv;
- X rv = WEXITSTATUS(j->status);
- X sprintf(buf, "Done (%d)", rv);
- X if (rv == 0)
- X *strchr(buf, '(') = 0;
- X j->state = JFREE;
- X } break;
- X
- X case JSIGNAL: {
- X int sig = WTERMSIG(j->status);
- X char *n = sigtraps[sig].mess;
- X if (n != NULL)
- X sprintf(buf, "%s", n);
- X else
- X sprintf(buf, "Signal %d", sig);
- X if (WIFCORED(j->status))
- X strcat(buf, " - core dumped");
- X j->state = JFREE;
- X } break;
- X
- X default:
- X s = "Hideous job state";
- X j->state = JFREE;
- X break;
- X }
- X shellf("%%%-2d%c %5d %-20s %s%s\n", j->job,
- X (j_current==j->job) ? '+' : (j_previous==j->job) ? '-' : ' ',
- X j->proc, s, j->com, (j->flags&XPIPEO) ? "|" : "");
- X}
- X
- X/* convert % sequence to job number */
- Xint
- Xj_lookup(cp)
- X char *cp;
- X{
- X register Proc *j;
- X int len, job = 0;
- X
- X if (*cp == '%') /* leading % is optional */
- X cp++;
- X switch (*cp) {
- X case '\0':
- X case '+':
- X job = j_current;
- X break;
- X
- X case '-':
- X job = j_previous;
- X break;
- X
- X case '0': case '1': case '2': case '3': case '4':
- X case '5': case '6': case '7': case '8': case '9':
- X job = atoi(cp);
- X break;
- X
- X case '?': /* %?string */
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state != JFREE && strstr(j->com, cp+1) != NULL)
- X job = j->job;
- X break;
- X
- X default: /* %string */
- X len = strlen(cp);
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state != JFREE && strncmp(cp, j->com, len) == 0)
- X job = j->job;
- X break;
- X }
- X if (job == 0)
- X errorf("%s: no such job\n", cp);
- X return job;
- X}
- X
- X/* are any stopped jobs ? */
- X#ifdef JOBS
- Xint
- Xj_stopped()
- X{
- X register Proc *j;
- X
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state == JSTOP)
- X return 1;
- X return 0;
- X}
- X#endif
- X
- X/* create new job number */
- Xstatic int
- Xj_newjob()
- X{
- X register Proc *j;
- X register int max = 0;
- X
- X j_lastjob ++;
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state != JFREE && j->job)
- X if (j->job > max)
- X max = j->job;
- X if (j_lastjob > max)
- X j_lastjob = max + 1;
- X return j_lastjob;
- X}
- X
- X/* search for job by job number */
- Xstatic Proc *
- Xj_search(job)
- X int job;
- X{
- X register Proc *j;
- X
- X for (j = procs; j != NULL; j = j->next)
- X if (j->state != JFREE && job == j->job && !(j->flags&XPIPEO))
- X return j;
- X return NULL;
- X}
- X
- END_OF_FILE
- if test 16759 -ne `wc -c <'sh/jobs.c'`; then
- echo shar: \"'sh/jobs.c'\" unpacked with wrong size!
- fi
- # end of 'sh/jobs.c'
- fi
- if test -f 'sh/trace.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sh/trace.c'\"
- else
- echo shar: Extracting \"'sh/trace.c'\" \(3039 characters\)
- sed "s/^X//" >'sh/trace.c' <<'END_OF_FILE'
- X/* NAME:
- X * trace.c - a simple trace facility
- X *
- X * SYNOPSIS:
- X * TRACE(level, (fmt [, ...]));
- X *
- X * DESCRIPTION:
- X * This module provides a simple trace facility via
- X * a call to checkpoint() which opens a log file and writes
- X * an entry and closes the log (so that process crashes
- X * won't destroy the log :-). checkpoint() takes options
- X * like printf(). If Trace_log is not initialized then
- X * stderr is used.
- X *
- X * The header file trace.h defines a macro TRACE() which
- X * is useful in that it allows checkpoint to be called
- X * based on the value of Trace_level, and the calls can be
- X * eliminated by undefining USE_TRACE.
- X *
- X * RETURN VALUE:
- X * None.
- X *
- X * FILES:
- X * None.
- X *
- X * SEE ALSO:
- X *
- X *
- X * BUGS:
- X *
- X *
- X * AMENDED:
- X * %E% %U% (%Y%)
- X *
- X * RELEASED:
- X * %D% %T% v%I%
- X *
- X * @(#)Copyright (c) 1990 Simon J. Gerraty.
- X */
- X#ifdef USE_TRACE
- X
- X#ifndef lint
- Xstatic char sccs_id[] = "%Z%%M% %I% %E% %U% (%Y%)";
- X#endif
- X
- X/* include files */
- X#include <stdio.h>
- X#ifdef __STDC__
- X# include <stdlib.h>
- X#endif
- X
- X#define EXTERN
- X#include "trace.h"
- X#undef EXTERN
- X
- X/* some useful #defines */
- X#ifndef ENTRY
- X# define ENTRY
- X# define LOCAL static
- X# define BOOLEAN int
- X#endif
- X#ifndef TRUE
- X# define TRUE 1
- X# define FALSE 0
- X#endif
- X#ifndef _P_
- X# if defined(__STDC__) || defined(PROTO)
- X# define _P_(p) p
- X# else
- X# define _P_(p) ()
- X# endif
- X#endif
- X
- X
- X/* NAME:
- X * checkpoint - write a logfile entry
- X *
- X * SYNOPSIS:
- X * checkpoint(fmt, ...)
- X *
- X * DESCRIPTION:
- X * This function takes a variable number or args
- X * like the printf(3S) family of functions.
- X *
- X * RETURN VALUE:
- X * None
- X */
- Xextern char * _CDECL strdup _P_((char *s));
- X
- X#ifdef __STDC__
- X# include <stdarg.h>
- X
- XENTRY void _CDECL
- Xcheckpoint(fmt)
- X char *fmt;
- X{
- X int c;
- X va_list arg_ptr;
- X FILE *fp;
- X register char *rcp;
- X char *mode;
- X static setup;
- X
- X va_start(arg_ptr, fmt);
- X#else /* __STDC__ */
- X# include <varargs.h>
- X
- XENTRY void _CDECL
- Xcheckpoint(va_alist)
- X va_dcl
- X{
- X extern char *getenv _P_((char *var));
- X char *fmt;
- X int c;
- X va_list arg_ptr;
- X FILE *fp;
- X register char *rcp;
- X char *mode;
- X static setup;
- X
- X va_start(arg_ptr);
- X fmt = va_arg(arg_ptr, char *);
- X#endif /* __STDC__ */
- X
- X /* 42 is a "magic" number */
- X if (setup == 42)
- X mode = "a";
- X else
- X {
- X if (Trace_level == 0 && (rcp = getenv("TRACE_LEVEL")))
- X Trace_level = atoi(rcp);
- X if (Trace_log == NULL || *Trace_log == '\0')
- X {
- X if (rcp = getenv("TRACE_LOG"))
- X Trace_log = strdup(rcp);
- X else
- X Trace_log = NULL;
- X }
- X setup = 42;
- X mode= "w";
- X }
- X if (Trace_log)
- X fp = fopen(Trace_log, mode);
- X else
- X fp = stderr;
- X if (fp != (FILE *)NULL)
- X {
- X vfprintf(fp, fmt, arg_ptr);
- X fputc('\n', fp);
- X if (fp == stderr)
- X fflush(fp);
- X else
- X fclose(fp);
- X }
- X}
- X
- X#endif /* USE_TRACE */
- X
- X/* This lot (for GNU-Emacs) goes at the end of the file. */
- X/*
- X * Local Variables:
- X * version-control:t
- X * comment-column:40
- X * End:
- X */
- END_OF_FILE
- if test 3039 -ne `wc -c <'sh/trace.c'`; then
- echo shar: \"'sh/trace.c'\" unpacked with wrong size!
- fi
- # end of 'sh/trace.c'
- fi
- echo shar: End of archive 2 \(of 9\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 9 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-