Beruflich Dokumente
Kultur Dokumente
Programming
Notes
The Bourne Shell
The Bourne shell is one of
a number of Unix shells (C
shell, Bash shell etc.). Like
the others, it is both a
command language and a
programming language. (A
shell is frequently called a
command interpreter.) As a
command language it
provides a user interface to
Unix/Linux. It executes
commands entered by the
user or from a file.
As a programming
language, each shell
provides I/O, variables,
conditionals, loops, and
switches. The syntax is
aimed at ease of use at a
terminal so that strings for
example do not have to be
Shell Notes. 1
quoted. Each shell
(Bourne, C, Bash etc) has
its own syntax.
"User-friendly''
commands
System
administration utilities
Application
utilities
Shell Notes. 2
some knowledge of other
Unix utilities such as grep,
tr, ed and awk.
A knowledge of shell
programming is essential
for the serious Unix user,
and will more than reward
the few hours invested in
exploring the shell, in time
saved developing new
commands and utilities.
Shell Programs
Shell commands may be
stored in a file. There are a
number of ways to execute
the commands in such a
file. One is to use the `sh'
command with the file as a
command line parameter
e.g. prog.sh is a file
containing 3 Unix
commands
Usage:
$ sh prog.sh
Code in prog.sh:
#!/bin/sh
pwd
ls -l
Shell Notes. 3
date
Commands may be
separated using newlines
as above or using
semicolons:
pwd ; ls -l ; date
$ chmod +x prog.sh
Make file executable - only
done once
$ prog.sh
Comments in Bourne
Shell
Shell Notes. 4
begin with a letter and are
composed of letters, digits
and underscores. They do
not have to be declared.
mybin=/usr/user/joe/jbin
name=`Bill
Bloggs'
Note that there are no
spaces around the '='
symbol.
Input
read
FILENAME
Shell Notes. 5
the last variable will contain
the rest of the line e.g.
read word1
word2 rest
with input
Output
The echo command is
used to display messages
and the values of variables.
The program echo simply
prints its command line
parameters on the
standard output.
echo "Hello
Second Science"
echo
Directory name is
$mybin
echo $name
echo
Filename is:
Shell Notes. 6
$FILENAME
echo -n
"Enter a file name: ''
$ cp prog
$mybin
The shell simply
substitutes the value of the
variable for each
occurrence of the variable
name. So you can use the
variable value as part of a
string:
$ ls -l
$mybin/prog
Shell Notes. 7
Variables are local to your
shell unless you 'mark'
them for export.
Program prog1.sh
contains:
export mybin
mybin=/usr/user/joe/jbin
current=/usr/user/joe
prog2.sh
# Call
prog2.sh
echo "Back in
prog1.sh''
echo "Value
of mybin'' $mybin
echo "Value
of current'' $current
Program prog2.sh
contains
echo
"Prog2.sh:
echo "Value
of mybin'' $mybin
echo "Value
of current'' $current
current=/usr/user
mybin=/bin
echo "Value
Shell Notes. 8
of mybin'' $mybin
Usage:
$ prog1.sh
Output:
Prog2.sh:
Value of
mybin /usr/user/joe/jbin
Value of
current
Value of
mybin /bin
Back in
prog1.sh
Value of
mybin /usr/user/joe/jbin
Value of
current /usr/user/joe
Shell Notes. 9
"mybin'' locally, but back in
prog1.sh, the value of
"mybin'' is unchanged.
Also, the variable "current''
has no value in prog2.sh,
since it was not marked for
export in prog1.sh.
Shell Notes. 10
that the right number of
parameters have been
provided.
date >
/tmp/record$$
ps -a >>
/tmp/record$$
The file will have a name
like /tmp/record102373.
A special parameter $* is
used to stand for all the
command line parameters
except $0.
So echo $* is equivalent to
echo $1, $2, $3 ....... e.g.
echo $*
Then executing prog.sh:
$ prog.sh
arg1 arg2 word3 abc
outputs
Shell Notes. 11
arg1 arg2
word3 abc
The shift command is
used to promote the
command line parameters
so that $2 becomes $1, $3
becomes $2 and so on.
Parameter $1 is lost.
Example:
$ prog word1
word2 word3
Code:
echo $1
shift
echo $1
shift
echo $1
Output:
word1
word2
word3
Shell Notes. 12
Other variables having a
special meaning to the
shell are:
HOME
Home directory -- default
argument for cd command.
Set up in the password file
/etc/passwd.
PATH
Search path for
commands. A list of
directories that is searched
by shell for command
binary files. By default it is
the current directory, /bin
and /usr/bin. The directory
names are separated by a
:
e.g. PATH=.:/bin:/usr/bin:
$HOME/bin
PS1
Primary shell prompt, by
default '$' (for Bourne
shell).
PS2
Secondary shell prompt, by
default '> ' (for Bourne
shell).
It is displayed when a
command such as a loop is
being entered over a
number of lines.
Shell Notes. 13
Any of the above variables
can be changed to suit
user requirements. These
changes would normally be
made in your login
command-file '.profile',
which is executed once by
the shell when you login.
The values of these
variables may be displayed
with echo:
$ echo
$PATH
$ echo
$HOME
Shell Notes. 14
Control Flow
The shell provides the
usual control flow
mechanisms associated
with structured
programming: for, while,
until, case, if-then, and if-
then-else structures.
General Format:
for var in
word1 word2
word3.......
do
commands
done
Example:
for i in
screen.c menu.c
compare.c
do
echo
"File : " $i
lpr $i
done
Shell Notes. 15
This example simply
displays the name of each
file in the list and sends the
file to the printer. The
commands between 'do'
and 'done' are executed
each time around the loop.
('do' and 'done' delimit the
body of the loop and are
also used in the while and
until structures.)
Shell Notes. 16
Usage:
$ create file1
file2 # Create is a
shell program
# to create
files
Code of create:
for File in $*
do
>$File
echo
$File created
done
for File
do
>$File
echo
$File created
done
Shell Notes. 17
loops over the command
line arguments as in the
previous example.
Shell Notes. 18
A useful example to show
some of the power of a
very simple shell program
is to develop a program
called, say, tel which
searches a file called
phone.dat in the home
directory, which has the
form:
Joe Bloggs
Dept. of Physics
6767
Fred Smith
5678
The tel program can
search for phone numbers
by name or any text in the
file.
Usage:
or
$ tel 6767
Output:
Shell Notes. 19
Joe Bloggs
Dept. Of Physics
6767
$
Code:
# tel program
for i in $*
do
grep –i
$i $HOME/phone.dat
done
It simply loops over the
command line arguments
and uses the 'grep'
program to search the file
phone.dat in the user's
home directory.
Shell Notes. 20
wildcard characters.
(These allow you build
regular expressions for
pattern matching.) The
commonest are * and ?.
Try:
echo *
echo *.c
It is important to realise
that the shell generates
this list of file names before
running the echo
command. As far as echo
is concerned, the user may
well have typed the list of
files on the command line.
Shell Notes. 21
for FILE in *.c
do
lpr
$FILE
cp
$FILE $HOME/backup
done
Shell Notes. 22
Another example of
developing a useful utility
using the for structure is a
shutdown procedure to
shutdown the operating
system, but give users a
warning beforehand, so
that they may save their
files and logout:
Usage:
$ shutdown
Code:
for i in 5 4 3 2
1
do
echo
"Going down in $i
minutes'' | /etc/wall
sleep 60
done
/etc/wall <<!
System
Going Down Now
Bye
!
kill -1 1
The program goes around
the for loop 5 times,
sleeping for 60 seconds
during each pass. 'sleep' is
a program that simply
causes your program to be
suspended for the number
of seconds specified i.e. it
does not waste CPU time.
Shell Notes. 23
writes a message to all
terminals, from its standard
input. Two methods of
providing the standard
input to '/etc/wall' are
shown.
Shell Notes. 24
system. Only the
superuser can do this.
General format:
while
command(s)
do
command(s)
done
The command after "while''
is executed and if it returns
true (exit status 0) then the
command(s) forming the
Shell Notes. 25
loop body are executed. An
endless loop may be
constructed, e.g. the asp
program (anti-sleep
program) to prevent the
your PC from going to
sleep:
#asp
program-you could get
bitten for using it !
while true
do
echo
"Sleeping.......
sleep
240 # Sleep for 4
minutes
done
until false
# Endless
loop
do
echo
"Sleeping..........''
sleep 240
# Sleep for 4
minutes
Shell Notes. 26
done
Another example of a
useful utility is the
watchfor program which
waits for a user to login
and writes a message to
his terminal and also echos
a message to your
terminal:
Usage:
$ watchfor
tom
tom has
logged on
Code:
# Watchfor
program
until who |
grep $1
do
sleep
120 # check
every 2 mins
done
# User has
logged on
write $1 <<!
Hello $1, Can
you contact me
!
echo $1 "has
logged on''
The pipeline " who | grep
Shell Notes. 27
$1 '' causes the output of
the who command to
become the input for grep,
which searches it for the
specified user e.g. tom in
this example.
Shell Notes. 28
The test command
A standard command
(sometimes built-in for
efficiency) called test is
available for testing various
conditions to do with
strings and files. It is one of
the most common ways to
control "while'', "until'' and
"if'' structures.
General form:
test
expression
test exp1 -o
exp2
test exp1 -a
exp2
It returns 0 if expression
evaluates to true, non-zero
otherwise. The "-o'' is used
for to combine two
expressions with logical
OR, "-a'' for logical AND.
Examples:
test -s File
True if File exists
and is non-empty
test -f File True if
File exists and is not a
directory
test -r FileTrue if
File is readable (also -w
Shell Notes. 29
for writeable)
test -d File
True if File is
directory
test -z Str True if
Str has zero length
test -n Str
True if Str has
non-zero length
test str1 = str2
True if strings are
equal
test n1 -eq n2
True if n1, n2
algebraically equal
(Also
-ne, -gt, -e,
-le, -lt for not
equals, etc. )
You can invert the above
conditions by using ! e.g.
test ! -d
true if file is not a
directory.
Shell Notes. 30
Sample Usage:
while test -r
/tmp/lockfile
do
sleep 5
done
This code waits for a file
called '/tmp/lockfile' to
disappear. This could be
used to implement a crude
form of semaphore system,
and is used in the program
myprint below to provide a
mechanism for preventing
users from trying to access
the printer simultaneously :
Usage:
$ myprint
file.c file2.c
Code:
# myprint
while test -r
/tmp/lockfile # Wait
until printer free
do
sleep 5
done
>/tmp/lockfile
# Lock printer
for i in $*
do
pr $i
> /dev/lp # pr file on
print device done
rm
Shell Notes. 31
/tmp/lockfile # Free
printer
This is a good example of
the shell being used to
create a useful "system''
program. Note it is not
foolproof, two users could
test for the presence of the
lockfile at the same time.
Shell Notes. 32
The if-then-fi
Structure
General format -- there are
3 possibilities:
if conditional-
command
then
commands
fi
if conditional-
command
then
commands
else
commands
fi
if conditional-
command
then
commands
elif conditional-
command
then
commands
else
commands
fi
Example 1
if test $# = 0
then
Shell Notes. 33
echo
"Usage: watchfor
username''
exit
fi
Here we check if no
command line parameter is
entered, displaying an error
message if this is so. This
check should be included
at the start of the
"watchfor'' program shown
earlier.
Shell Notes. 34
Example 2
if test $# -ne
2
then
echo
"Invalid 2 arguments
expected''
exit
else
echo " 2
parameters entered''
fi
It is often used to test
conditions about files. We
could use it to modify the
create program developed
earlier, so that it does not
truncate existing files:
# safecreate
program
for i in $*
do
if test -f $i
then
echo $i
"already exists''
else
>$i
done
This program loops over
the command line
parameters, testing if each
one exists, creating a file if
it does not already exist.
Shell Notes. 35
We could make the
program interactive,
prompting the user if the
file already exists, to find
out if he wishes to truncate
it:
Shell Notes. 36
# safecreate2
program
for i in $*
do
if test -f
$i
then
echo $i
"already exists''
echo -n
"Truncate it (Y|N)''
read ANS
if
test $ANS = Y -o $ANS
=y
then
>$i
elif
test $ANS = N -o $ANS
=n
then
continue #
Go around loop again
else
echo "Enter Y
or N''
Shell Notes. 37
safecreate2
$i
fi
else
>$i
fi
done
Here, we show the use of
elif, an abbreviation of else
if. You may have as many
elifs as required.
Shell Notes. 38
This feature, is probably
most often used when
processing files in
directories. Some of the
files may be directories
themselves and they in
turn may contain
subdirectories which
contain subdirectories and
so on. The sample
program lsdir is an
example. It lists the files in
a directory, and lists the
contents of subdirectories
and so on.
Usage:
$ lsdir
directory-name
Example:
$ lsdir
/usr/user/year3
Code:
# lsdir
program
PATH=/bin:/usr/bin:/use
r/usr/joe/bin
if test $# = 0
then
lsdir .
# Use
current directory
elif test ! -d
$1 # Check
if $1 is a directory
Shell Notes. 39
then
echo $1
"Not a directory''
ls -l $1
# List
the file
exit
else
for i in
$1/* # Loop over
files in $1
do
if
test -d $i # If it is a
directory
then
echo
"Directory: '' $i
( cd $i ; lsdir .
)
else
ls -l $i \#
ordinary file
fi
done
fi
If no arguments are
supplied to lsdir, it lists the
current directory by calling
itself recursively with
parameter ".''. The for
structure, takes the first
parameter, expands it to a
Shell Notes. 40
list of files in that directory
and loops over each file in
the list.
For example
lsdir
( cd $i ; lsdir
$i )
Shell Notes. 41
is not in a public 'bin'
( i.e. /bin or /usr/bin ) and
PATH has not been set
in .profile.
Shell Notes. 42
PATH=/bin:/usr/bin
monlist=/tmp/monlist
if test ! -r
$monlist
then
>$monlist
fi
while :
do
date >>
$monlist
echo " ''
>> $monlist
who >>
$monlist
echo " ''
>> $monlist
ps -a >>
$monlist
echo " ''
>> $monlist
sleep
300 # 5
minutes
done
It first checks to see if the
file '/tmp/monlist' exists,
creating it if it is not
present. This program uses
":'' after the "while'' which
always returns true, but is
built-in and so is more
efficient than using the
'true' program.
Shell Notes. 43
The echo command is
used to put blank lines in
the file between the output
of the various commands.
The program could be
executed a "daemon'', a
command which is always
running in the background.
Shell Notes. 44
The case Structure
Like the for structure, it is
based on pattern matching:
General Format:
case word in
pattern1)
command(s) ;;
pattern2)
command(s) ;;
esac
Note the double
semicolons terminating
each case.
case $# in
0) Echo
"No arguments
supplied'' ; exit ;;
2) Echo
"Correct '' ;;
*) Echo
"Incorrect number of
arguments'' ;;
esac
Shell Notes. 45
Example 2: An append
command
case $# in
1) cat
>> $1 ;;
2) cat
>> $2 < $1 ;;
*) echo
'Usage: append [from-
file] to-file' ;;
esac
Usage:
$ append
thisfile ontothatfile
case $1 in
-o) echo
"-o option entered'' ;;
-c) echo
"-c option entered'' ;;
esac
A range of characters may
be enclosed in []
Shell Notes. 46
[Yy]) echo "y or
Y entered'' ;;
Y|y|yes|Yes)
echo "Y or y or yes or Yes
entered'' ;;
# safecreate3
program using case
for i in $*
do
if test -f
$i
then
echo $i
"already exists''
echo -n
"Truncate it (Y|N) ''
read ANS
case $ANS in
y|Y) >$i ;;
n|N) continue
;; \# Go around
loop again
Shell Notes. 47
*) echo
"Enter Y or N''
safecreate3
$i ;;
esac
else
>$i
fi
done
Usage:
$ tidy f.c f2.c
t.c
or
$ tidy *
Shell Notes. 48
Code:
# Tidy program
if test $# -eq 0
then
echo "No
files specified"
exit
fi
# Display menu
cat <<!
Exit
x
Next file
n
Display file
t
Delete file
d
List file
l
Print file
p
!
# Process command line
parameters
for i in $*
do
echo "File : ''
$i # Display file
name
FIN=n
# Process each
file
while test
$FIN = n
do
echo -n "Enter
command: ''
Shell Notes. 49
read COM
case $COM in
n|N) break ;;
x|X) exit ;;
t|T) cat $i ;;
p|P) lp $i ;;
d|D) rm -i $i ;;
l|L) ls -l $i ;;
*) echo
"Unknown command
$COM'';;
esac
echo
echo -n
"Finished this file (y/n) ''
read FIN #
Only n is checked
done
# Next
command for this file
done
# Next file
Shell Notes. 50
echo commands, since
only one program has to be
loaded when using cat,
whereas if we use a list of
echo commands, each
command will have to be
loaded and executed
separately. Alternatively,
the menu could be stored
in a file and cat used to
display it, making it easy to
add a "show menu'' option
to the commands:
m) cat menu-
file ;;
Command
Substitution
This is a very powerful
mechanism allowing the
output of a command to be
used inline e.g.
today='date'
Shell Notes. 51
current='pwd'
Note that the quotes are
grave quotes (') and not
the usual single quotes
(').
Command substitution
allows you build some very
useful programs. Suppose
you wish to mail a group of
users a particular message
then if you create a file of
user names called name-
list:
joe
Shell Notes. 52
tom
year2
year3
..
..
one method of doing it is:
mail 'cat
name-list' < message
The shell executes the
command "cat name-list''
and the output is produced
inline just as if you entered:
mail 'cat
name-list' <<!
This is the
text
of the
message
.......
!
If you want to loop over the
files in a directory, in order
of last modification, then
Shell Notes. 53
you can use 'ls -t' to
produce the list of files and
use it inline, in a for loop:
Arithmetic
The Bourne shell provides
no built-in commands for
arithmetic operations.
However, a command
called 'expr' is available
which evaluates arithmetic
expressions on its
command line and outputs
the result to the standard
output.
$ expr 2 + 2
4
By executing the command
inline, we can perform
arithmetic on shell
variables. This can be used
to loop over command a
specific number of times.
For example, we could
rewrite the shutdown
command presented
earlier, to use $1 as the
number of minutes until
shutdown time. If no
command line parameters
are specified then 5 is
chosen as the default
number of minutes until
Shell Notes. 54
shutdown
Usage:
$ shutdown2
10 # Shut
system down in 10
mins
Shell Notes. 55
Code:
#shutdown2
program
if test $# = 0
then
count=5 #
Default is 5 minutes
else
count=$1
fi
i=1
tleft=$count
while test $i -le
$count
do
echo "System
going down in $tleft
minutes'' | /etc/wall
i='expr $i + 1'
# increment i
tleft='expr $tleft
- 1'
sleep 60
done
echo "System
going down now !!!!!''
| /etc/wall
kill -1 1
Output:
System going
down in 10 minutes
System going
down in 9 minutes
....
System going
Shell Notes. 56
down in 1 minutes
System going
down now !!!!!
$
Count gets the value of $1
( a string ), i gets the value
1, and tleft the value of
count for the time left.
Output of the 'expr'
command overwrites the
values of i and tleft each
time around the loop, until i
reaches the value of count.
1) The \
character
quotes the the
next character
e.g.
echo The
star
character: \*
Shell Notes. 57
echo The
backslash
character: \\
yields
The star
character: *
The
backslash
character: \
2) Single
quotes ' ' are
used to quote a
group of
characters:
echo
'***** Warning
**** ???? '
displays
*****
Warning
**** ????
3) Double
quotes are also
used but only
quote file
generation
characters *
and ? e.g.
echo
''$HOME has
no filenames
with a * in
them''
displays
/usr/user/j
Shell Notes. 58
oe has no
filenames with
a * in them
“Here Documents”
Shell Notes. 59
each file
specified
.
w
q
!
In the above example, the
word Unix is replaced by
UNIX in all files starting
'file.'. Two lines of text are
appended to each file.
Note that the dollar
character must be quoted
so that the shell does not
try to interpret it but passes
it on to ed directly.
Shell Notes. 60
containing the string
"Jones'' and deletes all
blank lines.
ed file <<!
1,\$s/\^Mr/Mister/
g/Jones/d
g/\^$/d
w
q
!
The g command instructs
ed to perform the
command on all lines,
the /Jones/ locates line
with the string "Jones''.
See the ed manual for
details. Note that the caret
has to be quoted since
otherwise it will be
interpreted as a shell
metacharacter (alternative
symbol for pipe) instead of
being passed to ed. This is
a good example of where
knowledge of a Unix utility,
ed in this case, can save a
lot of work. It is almost
always quicker to learn
how to use existing utilities
to do a job, than to write
even a simple C program
from scratch.
Shell Notes. 61
added to the password
file /etc/passwd for the user
specifying user name,
group, number etc.
Password entries have the
general form:
uname:pwd:uid:gid:misc:ho
me:shell
pwd: encrypted
password, empty if not set
e.g.
tom:xHyzio89-
ws:68:10:Tom Thumb
X2134:/usr/user/tom:/bin/s
h
A directory must be
created for the user (his
home directory), and the
user made the owner of
this directory. The
protection on this directory
may be set appropriately,
and the user added to the
appropriate group. A
command called {\bf
mkuser} can easily be
Shell Notes. 62
programmed to accomplish
the task. A simple form of
'mkuser' is given below. No
checks are carried out to
see if the name is already
in use and so on, but these
could easily be added. It
also assumes that users
will all have gid (group
identifier) 10. Only the
superuser can execute
'mkuser'.
Shell Notes. 63
Usage: $ mkuser jack
92
Code:
# mkuser program:
expects two
parameters
if test $# ! = 2
then
echo "Usage:
mkuser user-name
user-id''
exit
fi
# Add entry to
password file
ed /etc/passwd <<!
.a
$1::$2::10::/usr/us
er/$1:/bin/sh
.
w
q
!
mkdir /usr/user/$1
chown $1
/usr/user/$1
chgrp user
/user/usr/$1
chmod go-w
/usr/user/$1
This is a useful command
especially since the
password file entry is
Shell Notes. 64
complicated and it would
be easy to make a mistake
if you edit it by hand. Note
the "$'' is not quoted in the
"here document'' since we
want the shell to replace it
by the value of $1.
Signal Handling
In Unix, programs are sent
signals by the kernel in the
event of a program error,
(such as divide by zero, or
memory addressing error)
or when the user hits the
interrupt key (CTRL C), the
quit key (CTRL \), logs out
(Hangs up) or the user
generates a signal with the
'kill' command.
Shell Notes. 65
appropriate action. (This
can also be done from a C
program via the signal
system call.) Each signal
has an associated number,
there are approximately 19
different signals numbered
from 1 upwards. Some of
the common ones are:
1 Hangup
logout
2 Interrupt
Ctrl/C
3 Quit Ctrl \
10 Bus error
Memory
addressing error
15 Software
termination kill -15 pid
Shell Notes. 66
printer will be unusable.
The above trap command
illustrates how to prevent
this situation. It can be
interpreted as "if any of
signals 1, 2, 3, 15 are
received, then execute:
rm /etc/lockfile ; exit
thus freeing the printer and
terminating lpr. This line
should be inserted at the
start of the lpr program.
trap '' 1 2 3
trap 1 2 3
As an exercise you could
rewrite the 'asp' program,
to read a user code-word,
go into the sleep loop as
before, and when
interrupted, prompt for the
code-word terminating if it
matches that previously
entered, otherwise
returning to the sleep loop.
Efficiency of Shell
Programs
The efficiency of shell
programs can be improved
in a number of ways. By
setting the value of PATH
so that the shell only
searches the necessary
Shell Notes. 67
directories, in the right
order is one method. The
use of built-in commands
where possible such as ":''
instead of the program
'true' is another
improvement. Another
point is that many Unix
utilities such as 'cat', 'rm',
'ls' will themselves loop
over their command line
arguments. Where
possible, you should let the
utility do this, instead of
writing:
for i in $*
do
cat $i
done
cat $*
When you use a shell loop,
then the shell must locate
and load the program each
time around the loop.
When you write 'cat $*' the
'cat' program is only loaded
once, and it performs the
argument processing (after
the shell has expanded $*).
The use of a "here
document'' instead of a
series of 'echo' commands
is also worthwhile.
Shell Notes. 68
Normally when the shell
executes user commands,
it forks a subprocess for
each command. When the
command finishes, the
subprocess dies and
control returns to the shell.
There are two ways to
execute programs without
creating new
subprocesses.
exec newprog
Shell Notes. 69
'newprog' terminates,
control returns to the
calling program. This
allows the new program to
change variables in the
current shell. This is why
the login command file is
called '.profile', it is
executed as part of the
user's shell so that
variables that are set in
'.profile' remain set when
'.profile' terminates.
Debugging Shell
Programs
Finally, when debugging
shell programs, you can
invoke them "verbosely''
with
sh -v prog
set -v
set -n
set -x
Shell Notes. 70
provides an execution
trace. All flags may be
turned off by: set -
Shell Notes. 71