The shell may be used to read and execute commands
calls the shell to read commands from \fIfile.\fP
Such a file is called a \fIcommand procedure\fP
or \fIshell procedure.\fP
Arguments may be supplied with the call
and are referred to in \fIfile\fP
using the positional parameters
For example, if the file \fIwg\fP contains
UNIX files have three independent attributes,
\fIread,\fP \fIwrite\fP and \fIexecute.\fP
The UNIX command \fIchmod\fP (1) may be used
to make a file executable.
will ensure that the file \fIwg\fP has execute status.
Following this, the command
This allows shell procedures and programs
to be used interchangeably.
In either case a new process is created to
As well as providing names for the positional
the number of positional parameters in the call
is available as \fB$#\|.\fP
The name of the file being executed
is available as \fB$0\|.\fP
A special shell parameter \fB$\*(ST\fP
is used to substitute for all positional parameters
A typical use of this is to provide
nroff \(miT450 \(mims $\*(ST
which simply prepends some arguments
2.1\ Control\ flow\ -\ for
A frequent use of shell procedures is to loop
through the arguments (\fB$1, $2, \*(ZZ\fR)
executing commands once for each argument.
An example of such a procedure is
\fItel\fP that searches the file
that contains lines of the form
do grep $i /usr/lib/telnos; done
prints those lines in \fB/usr/lib/telnos\fR
that contain the string \fIfred\|.\fP
prints those lines containing \fIfred\fP
followed by those for \fIbert.\fP
The \fBfor\fP loop notation is recognized by the shell
\fBfor\fR \fIname\fR \fBin\fR \fIw1 w2 \*(ZZ\fR
\fBdo\fR \fIcommand-list\fR
A \fIcommand-list\fP is a sequence of one or more
simple commands separated or terminated by a newline or semicolon.
Furthermore, reserved words
like \fBdo\fP and \fBdone\fP are only
recognized following a newline or
\fIname\fP is a shell variable that is set
to the words \fIw1 w2 \*(ZZ\fR in turn each time the \fIcommand-list\fP
If \fBin\fR \fIw1 w2 \*(ZZ\fR
is executed once for each positional parameter;
that is, \fBin\fR \fI$\*(ST\fR is assumed.
Another example of the use of the \fBfor\fP
loop is the \fIcreate\fP command
ensures that two empty files
\fIalpha\fP and \fIbeta\fP exist
The notation \fI>file\fP may be used on its
own to create or clear the contents of a file.
Notice also that a semicolon (or newline) is required before \fBdone.\fP
2.2\ Control\ flow\ -\ case
A multiple way branch is provided for by the
\*(Ca2) cat \*(AP$2 <$1 ;;
\*(Ca\*(ST) echo \\'usage: append [ from ] to\\' ;;
is an \fIappend\fP command.
\fB$#\fP is the string \fI1\fP and
the standard input is copied onto the
using the \fIcat\fP command.
appends the contents of \fIfile1\fP
If the number of arguments supplied to
\fIappend\fP is other than 1 or 2
then a message is printed indicating
The general form of the \fBcase\fP command
\*(Ca\fIpattern\|\fB)\ \fIcommand-list\fB\|;;
The shell attempts to match
\fIword\fR with each \fIpattern,\fR
in the order in which the patterns
associated \fIcommand-list\fP is
of the \fBcase\fP is complete.
Since \*(ST is the pattern that matches any
string it can be used for the default case.
no check is made to ensure that only
The first match found defines the set of commands
In the example below the commands following
the second \*(ST will never be executed.
Another example of the use of the \fBcase\fP
construction is to distinguish
The following example is a fragment of a \fIcc\fP command.
\*(DC\(mi\*(ST) echo \\'unknown flag $i\\' ;;
\*(DC\*(ST.c) /lib/c0 $i \*(ZZ ;;
\*(DC\*(ST) echo \\'unexpected argument $i\\' ;;
To allow the same commands to be associated
with more than one pattern
the \fBcase\fP command provides
\*(Ca\(mix\*(VT\(miy) \*(ZZ
The usual quoting conventions apply
will match the character \fB?\|.\fP
The shell procedure \fItel\fP
in section 2.1 uses the file \fB/usr/lib/telnos\fR
An alternative is to include this
within the shell procedure as a \fIhere\fP document, as in,
the shell takes the lines between \fB\*(HE!\fR and \fB!\fR
as the standard input for \fIgrep.\fP
The string \fB!\fR is arbitrary, the document
being terminated by a line that consists
of the string following \*(HE\|.
Parameters are substituted in the document
before it is made available to \fIgrep\fP
as illustrated by the following procedure
is then equivalent to the command
and changes all occurrences of \fIstring1\fP
in \fIfile\fP to \fIstring2\|.\fP
Substitution can be prevented using \\
to quote the special character \fB$\fP
(This version of \fIedg\fP is equivalent to
the first except that \fIed\fP will print
a \fB?\fR if there are no occurrences of
Substitution within a \fIhere\fP document
may be prevented entirely by quoting
The document is presented
without modification to \fIgrep.\fP
If parameter substitution is not required
in a \fIhere\fP document this latter form
provides string-valued variables.
Variable names begin with a letter
and consist of letters, digits and
Variables may be given values by writing, for example,
user=fred\ box=m000\ acct=mh0000
which assigns values to the variables
\fBuser, box\fP and \fBacct.\fP
A variable may be set to the null string
The value of a variable is substituted
by preceding its name with \fB$\|;\fP
Variables may be used interactively
to provide abbreviations for frequently
will move the file \fIpgm\fP
from the current directory to the directory \fB/usr/fred/bin\|.\fR
A more general notation is available for parameter
and is used when the parameter name is
followed by a letter or digit.
will direct the output of \fIps\fR
to the file \fB/tmp/psa,\fR
would cause the value of the variable \fBtmpa\fP
Except for \fB$?\fP the following
are set initially by the shell.
\fB$?\fP is set after executing each command.
The exit status (return code)
of the last command executed
Most commands return a zero exit status
if they complete successfully,
otherwise a non-zero exit status is returned.
Testing the value of return codes is dealt with
later under \fBif\fP and \fBwhile\fP commands.
The number of positional parameters
Used, for example, in the \fIappend\fP command
to check the number of parameters.
The process number of this shell (in decimal).
Since process numbers are unique among
all existing processes, this string is
frequently used to generate
The process number of the last process
run in the background (in decimal).
The current shell flags, such as
\fB\(mix\fR and \fB\(miv\|.\fR
Some variables have a special meaning to the
shell and should be avoided for general
the shell looks at the file
specified by this variable
before it issues a prompt.
If the specified file has been modified
was last looked at the shell
\fIyou have mail\fP before prompting
This variable is typically set
in the file \fB.profile,\fP
in the user's login directory.
\s-1MAIL\s0=/usr/mail/fred
for the \fIcd\fP command.
The current directory is used to resolve
file name references that do not begin with
and is changed using the \fIcd\fP command.
makes the current directory \fB/usr/fred/bin\|.\fR
will print on the terminal the file \fIwn\fP
\fIcd\fP with no argument
This variable is also typically set in the
the user's login profile.
A list of directories that contain commands (the \fIsearch path\fR\|).
Each time a command is executed by the shell
a list of directories is searched
If \fB$\s-1PATH\s0\fP is not set
then the current directory,
\fB/bin\fP, and \fB/usr/bin\fP are searched by default.
Otherwise \fB$\s-1PATH\s0\fP consists of directory
names separated by \fB:\|.\fP
\s-1PATH\s0=\fB:\fP/usr/fred/bin\fB:\fP/bin\fB:\fP/usr/bin
specifies that the current directory
(the null string before the first \fB:\fP\|),
\fB/usr/fred/bin, /bin \fRand\fP /usr/bin\fR
are to be searched in that order.
In this way individual users
can have their own `private' commands
that are accessible independently
of the current directory.
If the command name contains a \fB/\fR then this directory search
is not used; a single attempt
is made to execute the command.
The primary shell prompt string, by default, `\fB$\ \fR'.
The shell prompt when further input is needed,
The set of characters used by \fIblank
interpretation\fR (see section 3.4).
The \fItest\fP command, although not part of the shell,
is intended for use by shell programs.
returns zero exit status if \fIfile\fP
exists and non-zero exit status otherwise.
In general \fItest\fP evaluates a predicate
and returns the result as its exit status.
Some of the more frequently used \fItest\fP
arguments are given here, see \fItest\fP (1)
for a complete specification.
test s true if the argument \fIs\fP is not the null string
test \(mif file true if \fIfile\fP exists
test \(mir file true if \fIfile\fP is readable
test \(miw file true if \fIfile\fP is writable
test \(mid file true if \fIfile\fP is a directory
2.6\ Control\ flow\ -\ while
the \fBfor\fP loop and the \fBcase\fP
branch are determined by data available to the shell.
A \fBwhile\fP or \fBuntil\fP loop
and an \fBif then else\fP branch
actions are determined by the exit status
A \fBwhile\fP loop has the general form
\fBwhile\fP \fIcommand-list\*1\fP
\fBdo\fP \fIcommand-list\*2\fP
The value tested by the \fBwhile\fP command
is the exit status of the last simple command
\fIcommand-list\*1\fP is executed;
if a zero exit status is returned then
otherwise, the loop terminates.
\fIshift\fP is a shell command that
renames the positional parameters
\fB$2, $3, \*(ZZ\fR as \fB$1, $2, \*(ZZ\fR
Another kind of use for the \fBwhile/until\fP
loop is to wait until some
external event occurs and then run
the termination condition is reversed.
will loop until \fIfile\fP exists.
Each time round the loop it waits for
5 minutes before trying again.
(Presumably another process
will eventually create the file.)
2.7\ Control\ flow\ -\ if
general conditional branch
that tests the value returned by the last simple command
The \fBif\fP command may be used
in conjunction with the \fItest\fP command
to test for the existence of a file as in
else \fIdo something else\fP
An example of the use of \fBif, case\fP
and \fBfor\fP constructions is given in
A multiple test \fBif\fP command
may be written using an extension of the \fBif\fP
The following example is the \fItouch\fP command
which changes the `last modified' time for a list
The command may be used in conjunction
with \fImake\fP (1) to force recompilation of a list
\*(DC\*(ST) if test \(mif $i
\*(DC then ln $i junk$$; rm junk$$
\*(DC then echo file \\\\\'$i\\\\\' does not exist
The \fB\(mic\fP flag is used in this command to
force subsequent files to be created if they do not already exist.
Otherwise, if the file does not exist, an error message is printed.
The shell variable \fIflag\fP
is set to some non-null string if the \fB\(mic\fP
make a link to the file and then remove it
thus causing the last modified date to be updated.
command1 \*(VT\*(VT command2
executes \fIcommand2\fP only if \fIcommand1\fP
In each case the value returned
is that of the last simple command executed.
Commands may be grouped in two ways,
\fB{\fI command-list\fB ; }\fR
\fB(\fI command-list\fB )\fR
In the first \fIcommand-list\fP is simply executed.
The second form executes \fIcommand-list\fP
executes \fIrm junk\fP in the directory
\fBx\fP without changing the current
directory of the invoking shell.
have the same effect but leave the invoking
shell in the directory \fBx.\fP
2.9\ Debugging\ shell\ procedures
The shell provides two tracing mechanisms
to help when debugging shell procedures.
The first is invoked within the procedure
(\fBv\fP for verbose) and causes lines of the
procedure to be printed as they are read.
It is useful to help isolate syntax errors.
It may be invoked without modifying the procedure
where \fIproc\fP is the name of the shell procedure.
This flag may be used in conjunction
with the \fB\(min\fP flag which prevents
execution of subsequent commands.
(Note that saying \fIset \(min\fP at a terminal
will render the terminal useless
until an end-of-file is typed.)
will produce an execution
Following parameter substitution
each command is printed as it is executed.
(Try these at the terminal to see
Both flags may be turned off by saying
and the current setting of the shell flags is available as \fB$\(mi\|.\fR
The following is the \fIman\fP command
which is used to print sections of the UNIX manual.
It is called, for example, as
In the first the manual section for \fIsh\fP
Since no section is specified, section 1 is used.
The second example will typeset (\fB\(mit\fP option)
the manual section for \fIed.\fP
The last prints the \fIfork\fP manual page
: \'colon is the comment command\'
: \'default is nroff ($N), section 1 ($s)\'
\*(DC[1\(mi9]\*(ST) s=$i ;;
\*(DC\(mi\*(ST) echo unknown flag \\\\\'$i\\\\\' ;;
\*(DC\*(ST) if test \(mif man$s/$i.$s
\*(DC then ${N}roff man0/${N}aa man$s/$i.$s
\*(DC else : \'look through all manual sections\'
\*(DC for j in 1 2 3 4 5 6 7 8 9
\*(DC do if test \(mif man$j/$i.$j
\*(DC \*(DOthen man $j $i
\*(DC \*(DO\*(THfound=yes
\*(DC \*(Cano) echo \\'$i: manual page not found\\'
Figure 1. A version of the man command