.H 1 "USING \|THE \|SHELL \|AS \|A \|COMMAND: \|SHELL \|PROCEDURES"
.H 2 "A \|Command's \|Environment"
.P
All the variables (with their associated values) that are known to
a command at the beginning of execution of that command constitute
its \f2environment\^\fP.
This environment includes variables that the command inherits
from its parent process and variables specified as
\f2keyword parameters\^\fP on the command line that
invokes the command.
.P
The variables that a shell passes to its child processes are those that
have been named as arguments to the %export% command.
The %export% command places the named variables in
the environments of both the shell \f2and\^\fP all its future
child processes.
.P
Keyword parameters are variable-value pairs that appear in the form of
assignments, normally \f2before\^\fP the procedure name on a command line
(see also %-k% flag in \(sc4.7).
Such variables are placed in the environment of the procedure being
invoked.
For example:
.CW
#	keycommand
echo $a $b
.CN
is a simple procedure that %echo%es the values of two variables;
if it is invoked as:
.CW
a=key1 b=key2 keycommand
.CN
then the resulting output is:
.CW
key1 key2
.CN
Keyword parameters are \f2not\^\fP counted as arguments to the procedure
and do not affect %$#%.
.P
A procedure may access the value of any variable in its environment;
however, if changes are made to the value of a variable, these
changes are not reflected in the environment\-they are local to
the procedure in question.
In order for these changes to be placed in
the environment that the procedure passes to \f2its\^\fP child processes, the
variable must be named as an argument to
the %export% command within that procedure (but see \(sc4.2 below).
To obtain a list of
variables
that have been made %export%able from the current shell, type:
.CW
export
.CN
(You will also get a list of variables that have been made
%readonly%\-see \(sc4.5 below).
To get a list of name-value pairs in the
current
environment, type:
.CW
env
.CN
.H 2 "Invoking \|the \|Shell"
.P
The shell is an ordinary command and may be invoked in the
same way as other commands:
.VL 25 3
.LI %sh%~\f2proc\^\fP~[~\f2arg~.\|.\|.\^\fP~]
A new instance of the shell is explicitly invoked to read
.I proc .
Arguments, if any, can be manipulated as described in \(sc4.3.
.LI %sh -v%\|~\f2proc\^\fP\|~[~\f2arg\|.\|.\|.\^\fP~]
This is equivalent to putting
%set -v%
at the beginning of
.I proc .
Similarly for the %x%, %e%, %u%, and %n% flags (\(sc3.9.3, \(sc4.7).
.LI \f2proc\^\fP~[~\f2arg~.\|.\|.\^\fP~]
If
.I proc\^
is marked executable,
and is not a compiled, executable program,
the effect is similar to that of
%sh% \f2proc\^\fP %[% \f2args .\|.\|.\^\fP %]%.
An advantage of this form is that
.I proc\^
may be found by the search procedure described in \(sc3.2 and \(sc3.4.2.
Also,
variables
that have been
%export%ed
in the shell will still be
%export%ed
from
.I proc\^
when this form is used (because the shell only
%fork%s
to read commands from
.I proc ).
Thus any changes made within \f2proc\^\fP to the values of
%export%ed
variables
will be passed on to subsequent commands invoked from
.I proc .
.br
.LE
.P
There are several shell invocation flags that are sometimes
useful for more advanced shell programming.
They are described in \(sc5.8.
.H 2 "Passing \|Arguments \|to \|the \|Shell"
.P
When a command line is scanned,
any character sequence of the form %$%\f2n\^\fP
is replaced by the
.I n th
argument to the shell,
counting the name of the shell procedure itself as %$0%.
This notation permits direct reference to the procedure name and to as many as
nine positional parameters (\(sc3.4.1).
Additional arguments can be processed using the
%shift%
command
or by using a
%for%
loop (\(sc4.4.4).
.P
The %shift% command
shifts arguments to the left; i.e., the value of %$1% is
thrown away, %$2% replaces %$1%, %$3% replaces %$2%, etc.;
the highest-numbered positional parameter becomes \f2unset\^\fP.
(%$0% is \f2never\^\fP %shift%ed.)~
For example, consider the shell procedure
%ripple%
below:
%echo%
writes its arguments to the standard output;
%while%
is discussed later (it is a looping command);
lines that begin with
%#%
are comments.
.CW
#	ripple command
while test $# != 0
do
	echo $1 $2 $3 $4 $5 $6 $7 $8 $9
	shift
done
.CN
.P
If the procedure were invoked by:
.CW
ripple a b c
.CN
it would print:
.CW
a b c
b c
c
.CN
.P
The notation %$*% causes substitution of
.I all\^
positional parameters except %$0%.
Thus, the
%echo%
line in the
%ripple%
example above could be
written more compactly as:
.CW
echo $*
.CN
.P
These two
%echo%
commands are \f2not\^\fP equivalent:
the first prints at most nine positional parameters;
the second prints \f2all\^\fP of the current positional parameters.
The %$*% notation is more concise and less error-prone.
One obvious application is in
passing an arbitrary number of arguments to a command such as
the %nroff% text formatter:
.CW
nroff -h -rT1 -T450 -cm $*
.CN
.P
It is important to understand the sequence of
actions used by the shell in
scanning command lines and substituting arguments.
The shell first reads input up to a new-line or semicolon, and then parses
that much of the input.
Variables are replaced by their values and then command substitution
(via
.I "grave accents" )
is attempted.
I/O redirection arguments are detected, acted upon, and deleted from the command line.
Next the shell scans the
resulting command line for
.I "internal field separators" ,
that is, for any characters specified by %IFS%
to break the command line
into distinct arguments;
\f2explicit\^\fP null arguments (specified by %""% or %''%) are retained,
while \f2implicit\^\fP null arguments resulting from
evaluation of variables that are null or not set
are removed.
Then file name generation occurs, with all meta-characters being expanded.
The resulting command line is executed by the shell.
.P
Sometimes, one builds command lines inside a shell
procedure.
In this case, one might want to have the shell re-scan
the command line after all the initial substitutions and
expansions are done.
The special command
%eval%
is available for this purpose;
%eval%
takes a command line as its argument and simply re-scans the line,
performing any variable or command substitutions that are specified.
Consider the following (simplified) situation:
.CW
command=who
output=' | wc -l'
eval $command $output
.CN
This segment of code results in the command line %who | wc -l% being
executed.
.P
The output of %eval% cannot be redirected;
uses of %eval%
can, however, be nested.
.H 2 "Control \|Commands"
.P
The shell provides several commands that implement
a variety of
control structures useful in creating shell procedures.
Before describing these structures, a few terms need to be defined.
.P
A
.I "simple command\^"
is as defined in \(sc3.1.
I/O redirection arguments can appear in a simple command line and are passed to
the shell,
.I not\^
to the command.
.P
A
.I command\^
is a simple command
or any of the shell control commands described below.
A
.I pipeline\^
is a sequence of one or more commands separated by %|%
(for historical reasons, %^% is a synonym for %|% in this context).
The standard output of each command but the last in a pipeline is connected
(by a
.I pipe (2))
to the standard input of the next command.
Each command
in a pipeline
is run separately; the shell waits for the last command to finish.
The exit status of a pipeline is non-zero if the exit
status of either the first or last process in the pipeline is non-zero.
(This is a bit weird, and may be changed in
the future.)~
.P
A
.I "command list\^"
is a sequence of one or more pipelines separated by %;%, %&%\^, %&&%\^, or %||%,
and optionally terminated by %;% or %&%\^.
A semicolon (%;%) causes sequential execution of the previous pipeline (i.e.,
the shell waits for the pipeline to finish before reading the next
pipeline), while
%&%\^ causes asynchronous execution of the
preceding pipeline;
both sequential and asynchronous execution are thus allowed.
An asynchronous pipeline continues execution until
it terminates voluntarily, or until its processes
are
%kill%ed.
In the first example below, the shell executes
%who%,
waits for it to terminate,
then executes
%date% and waits for it to terminate;
in the second example, the shell invokes both
commands in order, but does not wait for either one
to finish.
Figure~2 shows the actions of the shell involved in executing
these two command lists:
.CW
who >log; date
who >log& date&
.CN
.DF
.sp 4.1i
.ce
.bd R 3
\!.bd R 3
Figure 2
.br
.bd R
\!.bd R
.sp 1v
.DE
.P
More typical uses of %&%\^
include off-line printing,
background compilation,
and generation of jobs to be sent to other computers.
For example, if you type:
.CW -t
nohup cc prog.c&
.CN +t
.P
you may continue working while the C compiler runs in the background.
A command line ending with %&%\^
is immune to interrupts and quits,
but it is wise to make it immune to hang-ups as well.
The
%nohup%
command is used for this purpose.
Without
%nohup%,
if you hang up while
%cc%
in the above example
is still executing,
%cc%
will be killed and your output will disappear.
.P
.in +\w'~\(rh~\|'u
.ti -\w'~\(rh~\|'u
.I
~\(rh~\|The %&%\^
operator should be used with restraint,
especially on heavily-loaded systems.
Other users will not consider you a good citizen if you start up
a large number of simultaneous, asynchronous processes without a compelling reason
for doing so.
.R
.in -\w'~\(rh~\|'u
.P
The %&&%\^
and %||%
operators, which are of equal precedence (but lower than %&%\^
and %|%),
cause conditional execution of pipelines.
In
%cmd1 || cmd2%,
%cmd1%
is executed and its exit status examined.
Only if %cmd1% fails (i.e., has a non-zero exit status) is
%cmd2%
executed.
This is thus a more terse notation for:
.CW
if	cmd1
	test $? != 0
then
	cmd2
fi
.CN
.P
The %&&%\^
operator yields the complementary test:
in
%cmd1 && cmd2%,
the second command is executed
only if the first succeeds (has a zero exit status).
In the sequence below, each command is executed in order
until one fails:
.CW
cmd1 && cmd2 && cmd3 && ... && cmdn
.CN
.P
See
%writemail%
in \(sc6 for an example of use of %&&%\^.
.P
A simple command in a pipeline may be replaced by
a command list enclosed in
either parentheses or braces.
The output of all the commands so enclosed is combined
into one stream that becomes the input to the next command in the pipeline.
The following line prints two separate documents in a way similar to
that shown in
a previous example (\(sc3.7):
.CW
{ nroff -cm text1; nroff -cm text2; } | col | greek -Thp
.CN
See \(sc4.4.7 for further details on command grouping.
.P
All of the following commands are formally described in
.I sh (1).
.H 3 "Structured \|Conditional: \|%if%."
The shell provides structured conditional capability with the
%if%
command.
The simplest
%if%
command has the following form:
.CW -t
if \f2command list\^\fP
then \f2command list\^\fP
fi
.CN +t
The
command list
following
%if%
is executed and if the last command in the list has a \f2zero\^\fP exit status,
then the
command list
that follows
%then%
is executed;
%fi%
indicates the end of the
%if%
command.
.P
In order to cause an alternative set of commands to be executed in the case
where the
command list following %if% has a \f2non-zero\^\fP exit status, one may add an
%else%-clause
to the form given above.
This results in the following structure:
.CW -t
if \f2command list\^\fP
then \f2command list\^\fP
else \f2command list\^\fP
fi
.CN +t
Multiple tests can be achieved in an
%if%
command by using the
%elif% clause.
For example:
.CW
if	test -f "$1" # is $1 a file?
then	pr $1
elif	test -d "$1" # else, is $1 a directory?
then	(cd $1; pr *)
else	echo $1 is neither a file nor a directory
fi
.CN
The above example is executed as follows: if
the value of the first positional parameter is a file name,
then print that file; if not, then check to see if it is
the name of a directory.
If so, change to that
directory and print all the files there.
Otherwise, %echo% the error message.
.P
The
%if%
command may be nested (but be sure to end each one with a %fi%).
The new-lines in the above examples of
%if%
may be replaced by semicolons.
.P
The exit status of the
%if%
command is the exit status of the last command executed in any
%then% clause
or
%else% clause.
If no such command was executed,
%if%
returns a zero exit status.
.H 3 "Multi-way \|Branch: \|%case%."
A multiple way branch is provided by the
%case%
command.
The basic format of
%case%
is:
.CW -t
case \f2string\^\fP in
\f2pattern\^\fP) \f2command list\^\fP;;
.sp -.5v
  .
.sp -.5v
  .
.sp -.5v
  .
\f2pattern\^\fP) \f2command list\^\fP;;
esac
.CN +t
The shell tries to match
.I string\^
against each pattern in turn, using the same pattern-matching conventions
as in file-name generation (\(sc3.3).
If a match is found, the command list following the
matched pattern is executed; the
%;;%
serves as a break out of the %case% and is required
after each command list except the
last.
Note that only one pattern is ever matched, and that matches are
attempted in order, so that if %*% is the first pattern in as %case%,
no other patterns will ever be looked at.
.P
More than one pattern may be associated with a given command list by specifying
alternate patterns separated by %|%.
For example:
.CW
case $i in
	*.c) 	cc $i
		;;
	*.h|*.sh)	# do nothing
		;;
	*)	echo "$i of unknown type"
		;;
esac
.CN
In the above example, no action is taken for the second set of patterns
because the
.I null\^
command is specified;
%*% is used as a default pattern,
because it matches any word.
.P
The exit status of
%case%
is the exit status of the last command executed in the
%case%
command.
If no commands were executed, then
%case%
has a zero exit status.
.H 3 "Conditional \|Looping: \|%while% and \|%until%."
A
%while%
command has the general form:
.CW -t
while \f2command list\^\fP
do
	\f2command list\^\fP
done
.CN +t
The commands in the first command list are executed,
and if the exit status of the last command
in that list is zero, then the commands in the second list are executed.
This
sequence is repeated as long as the exit status of the first command list
is zero.
A loop can be executed as long as the first command list returns a non-zero exit
status by replacing %while% with %until%.
.P
Any
new-line
in the above example may be replaced by a semicolon.
The exit status of a
%while% (%until%)
command is the exit status of the last command
executed in the \f2second\^\fP command list.
If no such command is executed,
%while% (%until%)
has exit status zero.
.H 3 "Looping \|Over \|a \|List: \|%for%."
Often, one wishes to perform some set of operations
for each in a set of files, or execute some command
once for each of several arguments.
The
%for%
command can be used to accomplish this.
The
%for%
command has the format:
.CW -t
for \f2variable\^\fP in \f2word list\^\fP
do
	\f2command list\^\fP
done
.CN +t
where \f2word-list\^\fP is a list of strings separated by blanks.
The commands in the command list are executed once
for each word in the word list.
\f2Variable\^\fP takes on as its value each
word from the word list, in turn.
The word list is fixed after it is evaluated the first time.
For example, the following %for% loop
will cause each of the C source files %xec.c%,
%cmd.c%, and %word.c%
in the current directory to be
%diff%ed
with a file of the same name in
the directory
%/usr/src/cmd/sh%:
.CW
for cfile in xec cmd word
do	diff $cfile.c /usr/src/cmd/sh/$cfile.c
done
.CN
.P
One can omit the ``%in% word list''
part of a %for% command; this will
cause the current set of positional parameters to be used in place of the
word list.
This is very convenient when one wishes to write a command
that performs the same set of commands for each of an unknown number
of arguments.
See %null% in \(sc6 for an example of this feature.
.H 3 "Loop \|Control: \|%break% and \|%continue%."
The %break% command
can be used to terminate execution of a %while% or
a %for% loop;
%continue%
requests the execution of the next iteration of the loop.
These commands are effective only when they appear between
%do%
and
%done%.
.P
The %break% command
terminates execution of the smallest
(i.e., innermost)
enclosing
loop, causing execution to resume after the nearest following
unmatched
%done%.
Exit from
.I n\^
levels is obtained by
%break %\f2n\^\fP.
.P
The %continue% command
causes execution to resume at the nearest enclosing
%while%,
%until%,
or
%for%,
i.e., the one that begins
the innermost loop containing the
%continue%;
one can also specify an argument \f2n\^\fP to
%continue%
and execution will resume at the
.I n th
enclosing loop:
.CW
# This procedure is interactive; 'break' and 'continue'
# commands are used to allow the user to control data entry.
while true
do	echo "Please enter data"
	read response
	case "$response" in
		"done")	break	# no more data
			;;
		"")	continue
			;;
		*)
.CD -t
			\f2process the data here\fP
.CD +t
			;;
	esac
done
.CN
.H 3 "End-of-file \|and \|%exit%."
When the shell reaches the end-of-file,
it terminates execution, returning to its parent the exit status
of the last command executed prior to the end-of-file.
The
%exit%
command simply reads to the end-of-file and returns,
setting the exit status to the value of its argument, if any.
Thus, a procedure can be terminated
``normally''
by using %exit 0%.
.H 3 "Command \|Grouping: \|Parentheses \|and \|Braces."
There are two methods for grouping commands in the shell.
As mentioned in \(sc3.9.1,
parentheses %()% cause the shell to spawn a \f2sub-shell\^\fP
that reads the enclosed commands.
Both the right and left
parentheses
are recognized \f2wherever\^\fP they appear in a command line\-they
can appear as literal parentheses \f2only\^\fP by being quoted.
For example,
if you type %garble(stuff)% the shell interprets this
as four separate words: %garble%, %(%, %stuff%, and %)%.
.P
This sub-shell capability is useful if one wishes to perform
some operations without affecting
the values of variables in the current shell, or
to
temporarily
change directory and execute some commands in the
new directory without having to explicitly
return to
the current directory.
The current environment is passed to the sub-shell and
variables that are
%export%ed
in the current shell are also
%export%ed
in the sub-shell.
Thus:
.CW
current=`pwd`; cd /usr/man/docs/sh_tut;
nohup mm -Tlp sc? | lpr& cd $current
.CN
and:
.CW
(cd /usr/man/docs/sh_tut; nohup mm -Tlp sc? | lpr&)
.CN
accomplish the same result: a copy of this
tutorial is printed on the line printer;
however, the second example automatically puts you back in your
original working directory.
In the second example above, blanks or new-lines surrounding the
parentheses are allowed but not necessary.
The shell will prompt with %$PS2% if a %)% is expected.
See also the example in \(sc3.9.1.
.P
Braces %{}% may also be used to group commands together.
Both the left and the right brace are recognized \f2only\^\fP if they appear
as the first (unquoted)
word of a command.
The opening brace %{% may be followed by a new-line
(in which case the shell
will prompt
for more input).
Unlike parentheses,
no sub-shell is spawned for braces; the enclosed commands are simply read by the shell.
The braces are convenient when you wish to use the (sequential) output
of several commands as input to one command; see example in \(sc4.4 above.
.P
The exit status of a set of commands grouped by either parentheses or
braces is
the exit status of the last enclosed executed command.
.H 3 "Input/Output \|Redirection \|and \|Control \|Commands."
The shell normally does not \f2fork\^\fP when it recognizes the \f2control\^\fP commands
(other than parentheses)
described above.
However, each command
in a pipeline
is run as a separate process in order to direct input (output) to (from) each command.
Also, when redirection of input/output
is specified explicitly for a control command, a separate process is
spawned to execute that command.
Thus, when
%if%,
%while%,
%until%,
%case%,
or
%for%
are used in a pipeline consisting of
more than one command, the shell \f2fork\^\fPs
and a sub-shell runs the control command.
This has certain implications;
the most noticeable one is that
.I
any changes made to variables within the control command
are not effective once that control command finishes\^
.R
(similar to the effect of using parentheses to group commands).
The control commands run slightly slower when redirection is specified.
.H 3 "Transfer \|to \|Another \|File \|and \|Back: \|the \|Dot \|(\s+2.\s-2) \|Command."
A command line of the form:
.CW -t
\&. \f2proc\^\fP
.CN +t
causes the shell to read commands from
.I proc\^
without spawning a new process.
Changes made to variables in
.I proc\^
are in effect after the
.I dot\^
command finishes.
This is thus a good way to gather
a number of shell variable initializations
into one file.
Note that an
%exit%
command in a file executed
in this manner
will cause an exit from your current shell; if you are at
login level, you will be logged out.
.H 3 "Interrupt \|Handling: \|%trap%."
As noted in \(sc2.2,
a program may choose to
.I catch\^
an interrupt from the terminal,
\f2ignore\^\fP it completely,
or be terminated by it.
Shell procedures can use
the
%trap%
command
to obtain the same effects.
.CW -t
trap \f2arg signal list\^\fP
.CN +t
is the form of the
%trap%
command, where \f2arg\^\fP is a string to be interpreted as a command list and
.I "signal list\^"
consists of one or more signal numbers (as described in
.I signal (2)).
The commands in \f2arg\^\fP are scanned at least once, when the shell first
encounters the
%trap%
command.
Because of this, it is usually wise to use single rather
than double quotes to surround these commands.
The former inhibit
immediate command and variable substitution;
this becomes important, for instance, when one wishes to remove temporary files and
the names of those files have not yet been determined when the
trap command is first read by the shell.
The following procedure will print the name of the current directory
on the file %errdirect% when it is interrupted, thus giving
the user information as to how much of the job was done:
.CW
trap 'echo `pwd` >errdirect' 2 3 15
for i in /bin /usr/bin /usr/gas/bin
do
	cd $i
.CD -t
	   \f2commands to be executed in directory\^\fP $i \f2here\^\fP
.CD +t
done
.CN
while the same procedure with double rather than single quotes
(%trap "echo `pwd` >errdirect" 2 3 15%) will,
instead, print the name of the directory
from which the procedure was executed.
.P
Signal 11 may never be trapped, because the shell itself needs to catch it
to deal with memory allocation.
Zero is not a \*u signal, but is effectively interpreted by the
%trap%
command as a signal generated by exiting from a shell
(either via an %exit% command, or by ``falling through'' to the
end of a procedure).
If
.I arg\^
is not specified, then the action taken upon receipt
of any of the signals in
the
signal list
is reset to the default system action.
If
.I arg\^
is an explicit null string (%''% or %""%),
then the signals in
the
signal list
are \f2ignored\^\fP by the shell.
.P
The most frequent use of
%trap%
is to make sure that temporary files are removed upon
termination of a procedure.
The example of \(sc3.4.4 would be written more typically as follows:
.CW
temp=$HOME/temp/$$
trap 'rm $temp; trap 0; exit' 0 1 2 3 15
ls > $temp
.CD -t
     \f2commands that use\^\fP $temp \f2here\^\fP
.CN +t
In this example, whenever
signal 1 (hangup), 2 (interrupt), 3 (quit), or 15 (kill) is received by the shell
procedure, or
whenever the shell procedure is about to exit,
the commands enclosed between the single quotes will be executed.
The
%exit%
command must be included, or else the shell continues reading commands
where it left off when the signal was received.
The
%trap 0%
turns off the original trap on exits from the shell, so that
the
%exit%
command does not re-activate the execution of the trap commands.
.P
Sometimes it is useful to take advantage of
the fact that the shell continues reading commands after
executing the trap commands.
The following procedure takes each directory in the current directory, changes to it, prompts
with its name, and executes commands typed at the terminal until an
end-of-file (\f2control-d\^\fP) or an interrupt is received.
An end-of-file causes the %read% command to return a non-zero exit status, and
thus the %while% loop terminates and the next
directory cycle is initiated; an interrupt is ignored while executing the
requested commands, but causes termination of the
procedure when it is waiting
for input:
.CW
d=`pwd`
for i in *
do	if test -d $d/$i
	then	cd $d/$i
		while 	echo "$i:"
			trap exit 2
			read x
		do	trap : 2 	# ignore interrupts
			eval $x
		done
	fi
done
.CN
.P
Several
%trap%s
may be in effect at the same time; if multiple signals are received
simultaneously, they are serviced in ascending order.
To check what traps are currently set, type:
.CW
trap
.CN
.P
It is important to understand some things about the way in which the shell implements
the
%trap%
command in order not to be surprised.
When a signal (other than 11) is received by the shell, it is passed on
to whatever child processes are currently executing.
When those
(synchronous) processes terminate, normally or abnormally, the shell
.I then\^
polls any traps that happen to be set and executes the appropriate
%trap% commands.
This process is straightforward, except in the case of
traps set at the command (outermost, or login) level;
in this case, it is possible
that no child process is running, so the shell waits
for the termination of the first process spawned
.I after\^
the signal is received before it polls the traps.
.P
For internal commands, the shell normally polls traps on completion of the command;
an exception to this rule is made for the %read% command, for which traps
are serviced immediately, so that %read% can be interrupted while waiting
for input.
.H 2 "Special \|Shell \|Commands"
.P
There are several special commands that are \f2internal\^\fP to the
shell (some of which have already been mentioned).
These commands should be used in preference to other \*u commands whenever
possible, because they are, in general, faster and more efficient.
The shell does
not fork to execute these commands,
so no additional processes are spawned;
the trade-off for this efficiency is that redirection
of input/output is not allowed for most of these special commands.
.P
Several of the special commands have already been described in
\(sc4.4 because they affect the flow of control.
They are
%break%,
%continue%,
%exit%,
dot
(%.%),
and
%trap%.
The
%set%
command described in \(sc3.4.1 and \(sc3.9.3 is also a special command.
Descriptions of the remaining special commands are given here:
.VL 22 3
.LI %:%
The
.I null\^
command; this command does nothing; the exit status is zero (\f2true\^\fP).
.I Beware:\^
any arguments to the null command are parsed for syntactic
correctness; when in doubt, quote such arguments.
Parameter
substitution takes place, just as in other commands.
.LI %cd%~\f2arg\^\fP
Make
.I arg\^
the current directory.
If
.I arg\^
is not a valid directory, or the user is not authorized to
access it, a non-zero exit status is returned.
Specifying
%cd%
with no
.I arg\^
is equivalent to typing
%cd $HOME%.
.LI %exec%~\f2arg\^\fP~.\|.\|.
If
.I arg\^
is a command, then the shell executes it without forking.
No
new process is created.
Input/output redirection arguments \f2are\^\fP allowed
on the command line.
If \f2only\^\fP input/output redirection arguments appear,
then the input/output of the shell itself is modified accordingly.
See %merge% in \(sc6 for an example of this use of %exec%.
.LI %newgrp%~\f2arg\^\fP~.\|.\|.
The
.I newgrp (1)
command is executed, replacing the shell; \f2newgrp\^\fP in turn spawns
a new shell;
see
.I newgrp (1).
\f2Beware:\^\fP \|Only variables in the environment will be known in the
shell that is spawned by the
\f2newgrp\^\fP
command.
Any variables that were
%export%ed
will no longer be marked as such.
.LI %read%~\f2var\^\fP~.\|.\|.
One line (up to a
new-line)
is read from standard input and the first word is assigned to the first
variable, the second word to the second variable, and so on.
All left-over words are
assigned to the
.I last\^
variable.
The exit status of
%read%
is zero unless an
end-of-file
is read.
.LI %readonly%~\f2var\^\fP~.\|.\|.
The specified
variables
are made
%readonly%
so that no subsequent assignments may be made to them.
If no arguments are given, a list of all
%readonly%
and
of all %export%ed
variables is given.
.LI %test%
A conditional expression is evaluated.
More details are given in \(sc5.1 below.
.LI %times%
The accumulated user and system times for processes run from the current shell
are printed.
.LI %umask%~\f2nnn\^\fP
The user file creation mask is set to
.I nnn ;
see
.I umask (2)
for details.
If
.I nnn\^
is omitted, then the current value of the mask is printed.
.LI %wait%
The shell waits for all currently active child processes to terminate.
The exit status of %wait% is always zero.
.LE
.H 2 "Creation \|and \|Organization \|of \|Shell \|Procedures"
.P
A shell procedure can be created in two simple steps.
The first is that of building an ordinary text file.
The second is that of changing the
.I mode\^
of the file to make it
.I executable,\^
thus permitting it to be invoked by
.I "proc args" ,
rather than
%sh %\f2proc args\^\fP.
The second step may be omitted for a procedure to be used
once or twice and then discarded,
but is recommended for longer-lived ones.
Here is the entire input needed to set up a simple procedure
(the executable part of
%draft%
in \(sc6):
.CW
ed
a
nroff -rC3 -T450-12 -cm $*
.
w draft
q
chmod +x draft
.CN
.P
It may then be invoked as
%draft file1 file2%.
Note that shell procedures must always be at least readable, so that
the shell itself can read commands from the file.
.P
If
%draft%
were thus created in a directory whose name appears in the user's
%PATH%
variable,
the user could change working directories and still invoke the
%draft%
command.
.P
Shell procedures may be created dynamically.
A procedure may generate a file of commands,
invoke another instance of the shell to execute that file,
and then remove it.
An alternate approach is that of using the \f2dot\^\fP command
(%.%)
to make the current shell read commands from the new file, allowing use of
existing shell variables and
avoiding the spawning
of an additional process for another shell.
.P
Many users prefer to write shell procedures instead of C programs.
First, it is easy to create and maintain a shell procedure
because it is only a file of ordinary text.
Second, it has no corresponding object program that must
be generated and maintained.
Third, it is easy to create a procedure
on the fly,
use it a few times, and then remove it.
Finally, because shell procedures are usually short in length,
written in a high-level
programming language,
and kept only in their source-language form,
they are generally easy to find,
understand,
and modify.
.P
By convention,
directories that contain only commands and/or
shell procedures are usually named
.I bin .
Most groups of users sharing common interests
have one or more
.I bin\^
directories set up to
hold common procedures.
Some users have their
%PATH%
variable list several such directories.
Although you can have a number of such directories,
it is unwise to go overboard\-it may become
difficult to keep track of your environment,
and efficiency may suffer (\(sc7.3).
.H 2 "More \|about \|Execution \|Flags"
.P
There are several execution flags available in the shell that can
be useful in shell procedures:
.VL 9 3
.LI %-e%
The shell will exit immediately if any command
that it executes
exits with a non-zero exit status.
This flag is useful
for shell procedures composed of simple command lines; it is not
intended for use in conjunction with other conditional constructs.
.LI %-u%
When this flag is set,
the shell treats an unset variable as an error when
substituting that variable's value.
This flag can be used to effect a
global check on variables, rather than using conditional substitution (\(sc5.7)
to check each variable.
.LI %-t%
The shell exits after reading and executing the
commands on the remainder of the current input line.
.LI %-n%
This is a
.I "don't execute\^"
flag.
On occasion, one may want to check a procedure for syntax errors, but not
execute the commands in the procedure.
Writing
%set -nv%
at the beginning of the file will accomplish this.
.LI %-k%
All arguments of the form
\f2variable\^\fP%=%\f2value\^\fP
are treated as keyword parameters.
When this flag is \f2not\^\fP set, only
such arguments that appear
.I before\^
the command name are treated as keyword parameters.
.LE
