Added line is this color
Deleted line is this color
<h3 style="margin: auto 0in"><font face="Times New Roman">BOURNE SHELL
PROGRAMMING</font></h3>
<h3 style="margin: auto 0in"></h3>
<h3 style="margin: auto 0in"><font face="Times New Roman">Purpose Of This
Tutorial</font></h3>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This tutorial is written to help people understand some of the basics
of shell script programming, and hopefully to introduce some of the
possibilities of simple but powerful programming available under the bourne
shell. As such, it has been written as a basis for one-on-one or group
tutorials and exercises, and as a reference for subsequent use.</font></p>
<h3 style="margin: auto 0in"><font face="Times New Roman">Getting The Most
Recent Version Of This Tutorial</font></h3>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">The most recent version of this tutorial is available from:</font>
<a href="http://steve-parker.org/sh/sh.shtml"><font face="Times New Roman"
size="3">http://steve-parker.org/sh/sh.shtml</font></a><font face=
"Times New Roman" size="3">. Always check there for the latest copy.</font></p>
<h3 style="margin: auto 0in"><font face="Times New Roman">A Brief History of
sh</font></h3>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Steve Bourne, wrote the Bourne shell which appeared in the Seventh
Edition Bell Labs Research version of Unix.<br>
Many other shells have been written; this particular tutorial concentrates on
the Bourne and the Bourne Again shells.<br>
Other shells include the Korn Shell (ksh), the C Shell (csh), and variations
such as tcsh.<br>
This tutorial does <em>not</em> cover those shells. Maybe a future version will
cover ksh; I do not intend to write a tutorial for csh, as</font> <a href=
"http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/"><font face=
"Times New Roman" size="3">csh programming is considered
harmful</font></a><font face="Times New Roman" size="3">.</font></p>
<h3 style="margin: auto 0in"><font face="Times New Roman">Audience</font></h3>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This tutorial assumes some prior experience; namely:</font></p>
<ul type="disc">
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l9 level1 lfo1">
<font face="Times New Roman" size="3">Use of an interactive Unix
shell</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l9 level1 lfo1">
<font face="Times New Roman" size="3">Minimal programming knowledge - use of
variables, functions, is useful background knowledge</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l9 level1 lfo1">
<font face="Times New Roman" size="3">Understanding of how Unix commands are
structured, and competence in using some of the more common ones.</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l9 level1 lfo1">
<font face="Times New Roman" size="3">Programmers of C, Pascal, or any
programming language who can maybe read shell scripts, but don't feel they
understand exactly how they work.</font></li>
</ul>
<h3 style="margin: auto 0in"><font face="Times New Roman">Typographical
Conventions Used in This Tutorial</font></h3>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Significant words will be written in <em>italics</em> when mentioned
for the first time.</font></p>
<p><font face="Times New Roman" size="3">Code segments and script output will
be displayed as preformatted text.<br>
Command-line entries will be preceded by the Dollar sign ($). If your prompt is
different, enter the command:</font></p>
<pre>
<font size="2">PS1="$ " ; export PS1</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Then your interactions should match the examples given (such as $
./my-script.sh below).<br>
Script output (such as "Hello World" below) is displayed at the start of the
line.</font></p>
<pre>
<font size="2">$ echo '#!/bin/sh' > my-script.sh</font>
</pre>
<pre>
<font size="2">$ echo 'echo Hello World' >> my-script.sh</font>
</pre>
<pre>
<font size="2">$ chmod 755 my-script.sh</font>
</pre>
<pre>
<font size="2">$ ./my-script.sh</font>
</pre>
<pre>
<font size="2">Hello World</font>
</pre>
<pre>
<font size="2">$</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Entire scripts will be surrounded by thick horizontal rules and
include a reference where available to the plain text of the script:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/first.sh.txt"><font face="Times New Roman" size=
"3">first.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2"># This is a comment!</font>
</pre>
<pre>
<font size="2">echo Hello World<span style=
"mso-tab-count: 1"> </span># This is a comment, too!</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Note that to make a file executable, you must set the eXecutable bit,
and for a shell script, the Readable bit must also be set:</font></p>
<pre>
<font size="2">$ chmod a+rx first.sh</font>
</pre>
<table class="MsoNormalTable" style="width: 100%; mso-cellspacing: 1.5pt"
cellpadding="0" width="100%" border="0">
<tbody>
<tr style="mso-yfti-irow: 0; mso-yfti-lastrow: yes">
<td style=
"border-right: #ece9d8; padding-right: 0.75pt; border-top: #ece9d8; padding-left: 0.75pt; padding-bottom: 0.75pt; border-left: #ece9d8; padding-top: 0.75pt; border-bottom: #ece9d8; background-color: transparent">
<p class="MsoNormal" style="margin: 0in 0in 0pt"></p>
</td>
<td style=
"border-right: #ece9d8; padding-right: 0.75pt; border-top: #ece9d8; padding-left: 0.75pt; padding-bottom: 0.75pt; border-left: #ece9d8; padding-top: 0.75pt; border-bottom: #ece9d8; background-color: transparent">
<p class="MsoNormal" style="margin: 0in 0in 0pt; text-align: right" align=
"right"></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Shell script programming has a bit of a bad press amongst some Unix
systems administrators. This is normally because of one of two
things:</font></p>
<ul type="disc">
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l8 level1 lfo2">
<font face="Times New Roman" size="3">The speed at which an interpreted program
will run as compared to a C program, or even an interpreted Perl
program.</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l8 level1 lfo2">
<font face="Times New Roman" size="3">Since it is easy to write a simple
batch-job type shell script, there are a lot of poor quality shell scripts
around.</font></li>
</ul>
<p><font face="Times New Roman" size="3">It is partly due to this that there is
a certain machismo associated with creating <em>good</em> shell scripts.
Scripts which can be used as CGI programs, for example, without losing out too
much in speed to Perl (though both would lose to C, in many cases, were speed
the only criteria).<br>
There are a number of factors which can go into good, clean, quick, shell
scripts.</font></p>
<ul type="disc">
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l6 level1 lfo3">
<font face="Times New Roman" size="3">The most important criteria must be a
clear, readable layout.</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l6 level1 lfo3">
<font face="Times New Roman" size="3">Second is avoiding unnecessary
commands.</font></li>
</ul>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">A clear layout makes the difference between a shell script appearing
as "black magic" and one which is easily maintained and understood.<br>
You may be forgiven for thinking that with a simple script, this is not too
significant a problem, but two things here are worth bearing in
mind.</font></p>
<ol type="1">
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l4 level1 lfo4">
<font face="Times New Roman" size="3">First, a simple script will, more often
than anticipated, grow into a large, complex one.</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l4 level1 lfo4">
<font face="Times New Roman" size="3">Secondly, if nobody else can understand
how it works, you will be lumbered with maintaining it yourself for the rest of
your life!</font></li>
</ol>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Something about shell scripts seems to make them particularly likely
to be badly indented, and since the main control structures are if/then/else
and loops, indentation is critical for understanding what a script
does.</font></p>
<p><font face="Times New Roman" size="3">One of the major weaknesses in many
shell scripts is lines such as:</font></p>
<pre>
<font size="2">cat /tmp/myfile | grep "mystring"</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">which would run much faster as:</font></p>
<pre>
<font size="2">grep "mystring" /tmp/myfile</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Not much, you may consider; the OS has to load up the</font>
<code><span style="font-size: 10pt">/bin/grep</span></code> <font face=
"Times New Roman" size="3">executable, which is a reasonably small 75600 bytes
on my system, open a</font> <code><span style=
"font-size: 10pt">pipe</span></code> <font face="Times New Roman" size="3">in
memory for the transfer, load and run the</font> <code><span style=
"font-size: 10pt">/bin/cat</span></code> <font face="Times New Roman" size=
"3">executable, which is an even smaller 9528 bytes on my system, attach it to
the input of the pipe, and let it run.<br>
Of course, this kind of thing is what the OS is there for, and it's normally
pretty efficient at doing it. But if this command were in a loop being run many
times over, the saving of not locating and loading the</font>
<code><span style="font-size: 10pt">cat</span></code> <font face=
"Times New Roman" size="3">executable, setting up and releasing the pipe, can
make some difference, especially in, say, a CGI environment where there are
enough other factors to slow things down without the script itself being too
much of a hurdle. Some Unices are more efficient than others at what they call
"building up and tearing down processes" - ie, loading them up, executing them,
and clearing them away again. But however good your flavour of Unix is at doing
this, it'd rather not have to do it at all.</font></p>
<p><font face="Times New Roman" size="3">As a result of this, you may hear
mention of the Useless Use of Cat Award (UUoC), also known in some circles as
<strong>The Award For The Most Gratuitous Use Of The Word Cat In A Serious
Shell Script</strong> being bandied about on the</font> <code><span style=
"font-size: 10pt">comp.unix.shell</span></code> <font face="Times New Roman"
size="3">newsgroup from time to time. This is purely a way of peers keeping
each other in check, and making sure that things are done right.</font></p>
<p><font face="Times New Roman" size="3">Speaking of which, I would like to
recommend the</font> <code><span style=
"font-size: 10pt">comp.os.unix.shell</span></code> <font face="Times New Roman"
size="3">newsgroup to you, although its signal to noise ratio seems to have
decreased in recent years. There are still some real gurus who hang out there
with good advice for those of us who need to know more (and that's all of us!).
Sharing experiences is the key to all of this - the reason behind this tutorial
itself, and we can all learn from and contribute to open discussions about such
issues.<br>
Which leads me nicely on to something else: Don't <em>ever</em> feel too close
to your own shell scripts; by their nature, the source cannot be closed. If you
supply a customer with a shell script, s/he can inspect it quite easily. So you
might as well accept that it will be inspected by anyone you pass it to; use
this to your advantage with the</font> <a href=
"http://www.gnu.org/copyleft/gpl.html"><font face="Times New Roman" size=
"3">GPL</font></a> <font face="Times New Roman" size="3">- encourage people to
give you feedback and bugfixes for free!</font></p>
<h2 style="margin: 12pt 0in 3pt"><em>First Script</em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">For our first shell script, we'll just write a script which says
"Hello World". We will then try to get more out of a Hello World program than
any other tutorial you've ever read :-)<br>
Create a file (first.sh) as follows:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/first.sh.txt"><font face="Times New Roman" size=
"3">first.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2"># This is a comment!</font>
</pre>
<pre>
<font size="2">echo Hello World<span style=
"mso-tab-count: 1"> </span># This is a comment, too!</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">The first line tells Unix that the file is to be executed by /bin/sh.
This is the standard location of the Bourne shell on just about every Unix
system. If you're using GNU/Linux, /bin/sh is normally a symbolic link to
bash.</font></p>
<p><font face="Times New Roman" size="3">The second line begins with a special
symbol:</font> <code><span style="font-size: 10pt">#</span></code><font face=
"Times New Roman" size="3">. This marks the line as a comment, and it is
ignored completely by the shell.<br>
The only exception is when the <em>very first</em> line of the file starts
with</font> <code><span style="font-size: 10pt">#!</span></code> <font face=
"Times New Roman" size="3">- as ours does. This is a special directive which
Unix treats specially. It means that even if you are using csh, ksh, or
anything else as your interactive shell, that what follows should be
interpreted by the Bourne shell.<br>
Similarly, a Perl script may start with the line</font> <code><span style=
"font-size: 10pt">#!/usr/bin/perl</span></code> <font face="Times New Roman"
size="3">to tell your interactive shell that the program which follows should
be executed by perl. For Bourne shell programming, we shall stick to</font>
<code><span style="font-size: 10pt">#!/bin/sh.</span></code></p>
<p><font face="Times New Roman" size="3">The third line runs a command:</font>
<code><span style="font-size: 10pt">echo</span></code><font face=
"Times New Roman" size="3">, with two parameters, or arguments - the first is
"Hello"; the second is "World".<br>
Note that echo will automatically put a single space between its
parameters.<br>
The</font> <code><span style="font-size: 10pt">#</span></code> <font face=
"Times New Roman" size="3">symbol still marks a comment; the # and anything
following it is ignored by the shell.</font></p>
<p><font face="Times New Roman" size="3">now run</font> <code><span style=
"font-size: 10pt">chmod 755 first.sh</span></code> <font face="Times New Roman"
size="3">to make the text file executable, and run</font> <code><span style=
"font-size: 10pt">./first.sh</span></code><font face="Times New Roman" size=
"3">.<br>
Your screen should then look like this:</font></p>
<pre>
<font size="2">$ chmod 755 first.sh</font>
</pre>
<pre>
<font size="2">$ ./first.sh</font>
</pre>
<pre>
<font size="2">Hello World</font>
</pre>
<pre>
<font size="2">$</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">You will probably have expected that! You could even just
run:</font></p>
<pre>
<font size="2">$ echo Hello World</font>
</pre>
<pre>
<font size="2">Hello World</font>
</pre>
<pre>
<font size="2">$</font>
</pre>
<p><font face="Times New Roman" size="3">Now let's make a few changes.<br>
First, note that</font> <code><span style="font-size: 10pt">echo</span></code>
<font face="Times New Roman" size="3">puts ONE space between its parameters.
Put a few spaces between "Hello" and "World". What do you expect the output to
be? What about putting a TAB character between them?<br>
As always with shell programming, try it and see.<br>
The output is exactly the same! We are calling the</font> <code><span style=
"font-size: 10pt">echo</span></code> <font face="Times New Roman" size=
"3">program with two arguments; it doesn't care any more than</font>
<code><span style="font-size: 10pt">cp</span></code> <font face=
"Times New Roman" size="3">does about the gaps in between them.<br>
Now modify the code again:</font></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2"># This is a comment!</font>
</pre>
<pre>
<font size="2">echo "Hello<span style=
"mso-spacerun: yes"> </span>World"<span style=
"mso-tab-count: 1"> </span><span style=
"mso-spacerun: yes"> </span># This is a comment, too!</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This time it works. You probably expected that, too, if you have
experience of other programming languages. But the key to understanding what is
going on with more complex command and shell script, is to understand and be
able to explain: WHY?</font> <code><span style=
"font-size: 10pt">echo</span></code> <font face="Times New Roman" size="3">has
now been called with just ONE argument - the string "Hello World". It
prints this out exactly.<br>
The point to understand here is that the shell parses the arguments BEFORE
passing them on to the program being called. In this case, it strips the quotes
but passes the string as one argument.<br>
As a final example, type in the following script. Try to predict the outcome
before you run it:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/first2.sh.txt"><font face="Times New Roman"
size="3">first2.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2"># This is a comment!</font>
</pre>
<pre>
<font size="2">echo "Hello<span style=
"mso-spacerun: yes"> </span>World"<span style=
"mso-tab-count: 1"> </span><span style=
"mso-spacerun: yes"> </span># This is a comment, too!</font>
</pre>
<pre>
<font size="2">echo "Hello World"</font>
</pre>
<pre>
<font size="2">echo "Hello * World"</font>
</pre>
<pre>
<font size="2">echo Hello * World</font>
</pre>
<pre>
<font size="2">echo Hello<span style=
"mso-spacerun: yes"> </span>World</font>
</pre>
<pre>
<font size="2">echo "Hello" World</font>
</pre>
<pre>
<font size="2">echo Hello "<span style=
"mso-spacerun: yes"> </span>" World</font>
</pre>
<pre>
<font size="2">echo "Hello "*" World"</font>
</pre>
<pre>
<font size="2">echo `hello` world</font>
</pre>
<pre>
<font size="2">echo 'hello' world</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Is everything as you expected? If not, don't worry! These are just
some of the things we will be covering in this tutorial ... and yes, we will be
using more powerful commands than</font> <code><span style=
"font-size: 10pt">echo</span></code><font face="Times New Roman" size=
"3">!</font></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt"></p>
<h2 style="margin: 12pt 0in 3pt"><em>Variables - Part I</em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Just about every programming language in existence has the concept of
<em>variables</em> - a symbolic name for a chunk of memory to which we can
assign values, read and manipulate its contents. The bourne shell is no
exception, and this section introduces idea. This is taken further in</font>
<a href="http://steve-parker.org/sh/variables2.shtml"><font face=
"Times New Roman" size="3">Variables - Part II</font></a> <font face=
"Times New Roman" size="3">which looks into variables which are set for us by
the environment.<br>
Let's look back at our first Hello World example. This could be done using
variables (though it's such a simple example that it doesn't really warrant
it!)<br>
Note that there must be no spaces around the "=" sign:</font>
<code><span style="font-size: 10pt">VAR=value</span></code> <font face=
"Times New Roman" size="3">works;</font> <code><span style=
"font-size: 10pt">VAR = value</span></code> <font face="Times New Roman" size=
"3">doesn't work. In the first case, the shell sees the "=" symbol and treats
the command as a variable assignment. In the second case, the shell assumes
that VAR must be the name of a command and tries to execute it.<br>
If you think about it, this makes sense - how else could you tell it to run the
command VAR with its first argument being "=" and its second argument being
"value"?<br>
Enter the following code into var1.sh:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/var.sh.txt"><font face="Times New Roman" size=
"3">var.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">MY_MESSAGE="Hello World"</font>
</pre>
<pre>
<font size="2">echo $MY_MESSAGE</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This assigns the string "Hello World" to the variable</font>
<code><span style="font-size: 10pt">MY_MESSAGE</span></code> <font face=
"Times New Roman" size="3">then</font> <code><span style=
"font-size: 10pt">echo</span></code><font face="Times New Roman" size="3">es
out the value of the variable.<br>
Note that we need the quotes around the string Hello World. Whereas we could
get away with</font> <code><span style="font-size: 10pt">echo Hello
World</span></code> <font face="Times New Roman" size="3">because echo will
take any number of parameters, a variable can only hold one value, so a string
with spaces must be quoted to that the shell knows to treat it all as one.
Otherwise, the shell will try to execute the command</font> <code><span style=
"font-size: 10pt">World</span></code> <font face="Times New Roman" size=
"3">after assigning</font> <code><span style=
"font-size: 10pt">MY_MESSAGE=Hello</span></code></p>
<p><font face="Times New Roman" size="3">The shell does not care about types of
variables; they may store strings, integers, real numbers - anything you
like.<br>
People used to Perl may be quite happy with this; if you've grown up with C,
Pascal, or worse yet Ada, this may seem quite strange.<br>
In truth, these are all stored as strings, but routines which expect a number
can treat them as such.<br>
If you assign a string to a variable then try to add 1 to it, you will not get
away with it:</font></p>
<pre>
<font size="2">$ x="hello"</font>
</pre>
<pre>
<font size="2">$ y=`expr $x + 1`</font>
</pre>
<pre>
<font size="2">expr: non-numeric argument</font>
</pre>
<pre>
<font size="2">$</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Since the external program</font> <code><span style=
"font-size: 10pt">expr</span></code> <font face="Times New Roman" size="3">only
expects numbers. But there is no syntactic difference between:</font></p>
<pre>
<font size="2">MY_MESSAGE="Hello World"</font>
</pre>
<pre>
<font size="2">MY_SHORT_MESSAGE=hi</font>
</pre>
<pre>
<font size="2">MY_NUMBER=1</font>
</pre>
<pre>
<font size="2">MY_PI=3.142</font>
</pre>
<pre>
<font size="2">MY_OTHER_PI="3.142"</font>
</pre>
<pre>
<font size="2">MY_MIXED=123abc</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Note though that special characters must be properly escaped to avoid
interpretation by the shell.<br>
This is discussed further in</font> <a href=
"http://steve-parker.org/sh/escape.shtml"><font face="Times New Roman" size=
"3">Escape Characters</font></a><font face="Times New Roman" size=
"3">.</font></p>
<p><font face="Times New Roman" size="3">We can interactively set variable
names using the</font> <code><span style="font-size: 10pt">read</span></code>
<font face="Times New Roman" size="3">command; the following script asks you
for your name then greets you personally:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/var2.sh.txt"><font face="Times New Roman" size=
"3">var2.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">echo What is your name?</font>
</pre>
<pre>
<font size="2">read MY_NAME</font>
</pre>
<pre>
<font size="2">echo "Hello $MY_NAME - hope you're well."</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Mario Bacinsky kindly pointed out to me that I had originally missed
out the double-quotes in line 3, which meant that the single-quote in the word
"you're" was unmatched, causing an error. It is this kind of thing which can
drive a shell programmer crazy, so watch out for them!</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This is using the shell-builtin command</font> <code><span style=
"font-size: 10pt">read</span></code> <font face="Times New Roman" size=
"3">which reads a line from standard input into the variable supplied.<br>
Note that even if you give it your full name and don't use double quotes around
the</font> <code><span style="font-size: 10pt">echo</span></code> <font face=
"Times New Roman" size="3">command, it still outputs correctly. How is this
done? With the</font> <code><span style=
"font-size: 10pt">MY_MESSAGE</span></code> <font face="Times New Roman" size=
"3">variable earlier we had to put double quotes around it to set it.<br>
What happens, is that the</font> <code><span style=
"font-size: 10pt">read</span></code> <font face="Times New Roman" size=
"3">command automatically places quotes around its input, so that spaces are
treated correctly. (You will need to quote the output, of course - e.g.</font>
<code><span style="font-size: 10pt">echo "$MY_MESSAGE"</span></code><font face=
"Times New Roman" size="3">).</font> <a name="scope"></a></p>
<h2 style="margin: 12pt 0in 3pt"><em>Scope of Variables</em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Variables in the bourne shell do not have to be declared, as they do
in languages like C. But if you try to read an undeclared variable, the result
is the empty string. You get no warnings or errors. This can cause some subtle
bugs - if you assign</font> <code><span style=
"font-size: 10pt">MY_OBFUSCATED_VARIABLE=Hello</span></code> <font face=
"Times New Roman" size="3">and then</font> <code><span style=
"font-size: 10pt">echo $MY_OSFUCATED_VARIABLE</span></code><font face=
"Times New Roman" size="3">, you will get nothing (as the second OBFUSCATED is
mis-spelled).</font></p>
<p><font face="Times New Roman" size="3">There is a command called</font>
<code><span style="font-size: 10pt">export</span></code> <font face=
"Times New Roman" size="3">which has a fundamental effect on the scope of
variables. In order to really know what's going on with your variables, you
will need to understand something about how this is used.</font></p>
<p><font face="Times New Roman" size="3">Create a small shell script,</font>
<code><span style="font-size: 10pt">myvar2.sh</span></code><font face=
"Times New Roman" size="3">:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/myvar2.sh.txt"><font face="Times New Roman"
size="3">myvar2.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">echo "MYVAR is: $MYVAR"</font>
</pre>
<pre>
<font size="2">MYVAR="hi there"</font>
</pre>
<pre>
<font size="2">echo "MYVAR is: $MYVAR"</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Now run the script:</font></p>
<pre>
<font size="2">$ ./myvar2.sh</font>
</pre>
<pre>
<font size="2">MYVAR is:</font>
</pre>
<pre>
<font size="2">MYVAR is: hi there</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">MYVAR hasn't been set to any value, so it's blank. Then we give it a
value, and it has the expected result.<br>
Now run:</font></p>
<pre>
<font size="2">$ MYVAR=hello</font>
</pre>
<pre>
<font size="2">$ ./myvar2.sh</font>
</pre>
<pre>
<font size="2">MYVAR is:</font>
</pre>
<pre>
<font size="2">MYVAR is: hi there</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">It's still not been set! What's going on?!<br>
When you call</font> <code><span style=
"font-size: 10pt">myvar2.sh</span></code> <font face="Times New Roman" size=
"3">from your interactive shell, a new shell is spawned to run the script. This
is partly because of the</font> <code><span style=
"font-size: 10pt">#!/bin/sh</span></code> <font face="Times New Roman" size=
"3">line at the start of the script, which we discussed</font> <a href=
"http://steve-parker.org/sh/first.shtml"><font face="Times New Roman" size=
"3">earlier</font></a><font face="Times New Roman" size="3">.<br>
We need to</font> <code><span style="font-size: 10pt">export</span></code>
<font face="Times New Roman" size="3">the variable for it to be inherited by
another program - including a shell script. Type:</font></p>
<pre>
<font size="2">$ export MYVAR</font>
</pre>
<pre>
<font size="2">$ ./myvar2.sh</font>
</pre>
<pre>
<font size="2">MYVAR is: hello</font>
</pre>
<pre>
<font size="2">MYVAR is: hi there</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Now look at line 3 of the script: this is changing the value of</font>
<code><span style="font-size: 10pt">MYVAR</span></code><font face=
"Times New Roman" size="3">. But there is no way that this will be passed back
to your interactive shell. Try reading the value of</font> <code><span style=
"font-size: 10pt">MYVAR</span></code><font face="Times New Roman" size=
"3">:</font></p>
<pre>
<font size="2">$ echo $MYVAR</font>
</pre>
<pre>
<font size="2">hello</font>
</pre>
<pre>
<font size="2">$</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Once the shell script exits, its environment is destroyed. But</font>
<code><span style="font-size: 10pt">MYVAR</span></code> <font face=
"Times New Roman" size="3">keeps its value of</font> <code><span style=
"font-size: 10pt">hello</span></code> <font face="Times New Roman" size=
"3">within your interactive shell.<br>
In order to receive environment changes back from the script, we must
<em>source</em> the script - this effectively runs the script within our own
interactive shell, instead of spawning another shell to run it.<br>
We can source a script via the "." command:</font></p>
<pre>
<font size="2">$ MYVAR=hello</font>
</pre>
<pre>
<font size="2">$ echo $MYVAR</font>
</pre>
<pre>
<font size="2">hello</font>
</pre>
<pre>
<font size="2">$ . ./myvar2.sh</font>
</pre>
<pre>
<font size="2">MYVAR is: hello</font>
</pre>
<pre>
<font size="2">MYVAR is: hi there</font>
</pre>
<pre>
<font size="2">$ echo $MYVAR</font>
</pre>
<pre>
<font size="2">hi there</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">The change has now made it out into our shell again! This is how
your</font> <code><span style="font-size: 10pt">.profile</span></code>
<font face="Times New Roman" size="3">or</font> <code><span style=
"font-size: 10pt">.bash_profile</span></code> <font face="Times New Roman"
size="3">file works, for example.<br>
Note that in this case, we don't need to</font> <code><span style=
"font-size: 10pt">export MYVAR</span></code><font face="Times New Roman" size=
"3">.<br>
Thanks to <em>sway</em> for pointing out that I'd originally said</font>
<code><span style="font-size: 10pt">echo MYVAR</span></code> <font face=
"Times New Roman" size="3">above, not</font> <code><span style=
"font-size: 10pt">echo $MYVAR</span></code> <font face="Times New Roman" size=
"3">as it should be.</font></p>
<p><font face="Times New Roman" size="3">One other thing worth mentioning at
this point about variables, is to consider the following shell
script:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">echo "What is your name?"</font>
</pre>
<pre>
<font size="2">read USER_NAME</font>
</pre>
<pre>
<font size="2">echo "Hello $USER_NAME"</font>
</pre>
<pre>
<font size="2">echo "I will create you a file called $USER_NAME_file"</font>
</pre>
<pre>
<font size="2">touch $USER_NAME_file</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Think about what result you would expect. For example, if you enter
"steve" as your USER_NAME, should the script create</font> <code><span style=
"font-size: 10pt">steve_file</span></code><font face="Times New Roman" size=
"3">?<br>
Actually, no. This will cause an error unless there is a variable called</font>
<code><span style="font-size: 10pt">USER_NAME_file</span></code><font face=
"Times New Roman" size="3">. The shell does not know where the variable ends
and the rest starts. How can we define this?<br>
The answer is, that we enclose the variable itself in curly
brackets:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/user.sh.txt"><font face="Times New Roman" size=
"3">user.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">echo "What is your name?"</font>
</pre>
<pre>
<font size="2">read USER_NAME</font>
</pre>
<pre>
<font size="2">echo "Hello $USER_NAME"</font>
</pre>
<pre>
<font size="2">echo "I will create you a file called ${USER_NAME}_file"</font>
</pre>
<pre>
<font size="2">touch "${USER_NAME}_file"</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">The shell now knows that we are referring to the variable</font>
<code><span style="font-size: 10pt">USER_NAME</span></code> <font face=
"Times New Roman" size="3">and that we want it suffixed with</font>
<code><span style="font-size: 10pt">_file</span></code><font face=
"Times New Roman" size="3">. This can be the downfall of many a new shell
script programmer, as the source of the problem can be difficult to track
down.</font></p>
<p><font face="Times New Roman" size="3">Also note the quotes around</font>
<code><span style="font-size: 10pt">"${USER_NAME}_file"</span></code>
<font face="Times New Roman" size="3">- if the user entered "Steve Parker"
(note the space) then without the quotes, the arguments passed to</font>
<code><span style="font-size: 10pt">touch</span></code> <font face=
"Times New Roman" size="3">would be</font> <code><span style=
"font-size: 10pt">Steve</span></code> <font face="Times New Roman" size=
"3">and</font> <code><span style="font-size: 10pt">Parker_file</span></code>
<font face="Times New Roman" size="3">- that is, we'd effectively be
saying</font> <code><span style="font-size: 10pt">touch Steve
Parker_file</span></code><font face="Times New Roman" size="3">, which is two
files to be</font> <code><span style=
"font-size: 10pt">touch</span></code><font face="Times New Roman" size="3">ed,
not one. The quotes avoid this. Thanks to Chris for highlighting
this.</font></p>
<h2 style="margin: 12pt 0in 3pt"><em>Wildcards</em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Wildcards are really nothing new if you have used Unix at all
before.<br>
It is not necessarily obvious how they are useful in shell scripts though. This
section is really just to get the old grey cells thinking how things look when
you're in a shell script - predicting what the effect of using different
syntaxes are. This will be used later on, particularly in the</font> <a href=
"http://steve-parker.org/sh/loops.shtml"><font face="Times New Roman" size=
"3">Loops</font></a> <font face="Times New Roman" size="3">section.<br>
Think first how you would copy all the files from</font> <code><span style=
"font-size: 10pt">/tmp/a</span></code> <font face="Times New Roman" size=
"3">into</font> <code><span style=
"font-size: 10pt">/tmp/b</span></code><font face="Times New Roman" size="3">.
All the .txt files? All the .html files?<br>
Hopefully you will have come up with:</font></p>
<pre>
<font size="2">$ cp /tmp/a/* /tmp/b/</font>
</pre>
<pre>
<font size="2">$ cp /tmp/a/*.txt /tmp/b/</font>
</pre>
<pre>
<font size="2">$ cp /tmp/a/*.html /tmp/b/</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Now how would you list the files in</font> <code><span style=
"font-size: 10pt">/tmp/a/</span></code> <font face="Times New Roman" size=
"3">without using</font> <code><span style="font-size: 10pt">ls
/tmp/a/</span></code><font face="Times New Roman" size="3">?<br>
How about</font> <code><span style="font-size: 10pt">echo
/tmp/a/*</span></code><font face="Times New Roman" size="3">? What are the two
key differences between this and the</font> <code><span style=
"font-size: 10pt">ls</span></code> <font face="Times New Roman" size=
"3">output? How can this be useful? Or a hinderance?<br>
How could you rename all .txt files to .bak? Note that</font></p>
<pre>
<font size="2">$ mv *.txt *.bak</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">will not have the desired effect; think about how this gets expanded
by the shell before it is passed to</font> <code><span style=
"font-size: 10pt">mv</span></code><font face="Times New Roman" size="3">. Try
this using</font> <code><span style="font-size: 10pt">echo</span></code>
<font face="Times New Roman" size="3">instead of</font> <code><span style=
"font-size: 10pt">mv</span></code> <font face="Times New Roman" size="3">if
this helps.<br>
We will look into this further later on, as it uses a few concepts not yet
covered.</font></p>
<h2 style="margin: 12pt 0in 3pt"><em>Escape Characters</em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Certain characters are significant to the shell; we have seen, for
example, that the use of double quotes (") characters affect how spaces and TAB
characters are treated, for example:</font></p>
<pre>
<font size="2">$ echo Hello<span style=
"mso-spacerun: yes"> </span>World</font>
</pre>
<pre>
<font size="2">Hello World</font>
</pre>
<pre>
<font size="2">$ echo "Hello<span style=
"mso-spacerun: yes"> </span>World"</font>
</pre>
<pre>
<font size="2">Hello<span style="mso-spacerun: yes"> </span>World</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">So how do we display:</font> <code><span style=
"font-size: 10pt">Hello "World"</span></code> <font face="Times New Roman"
size="3">?</font></p>
<pre>
<font size="2">$ echo "Hello<span style=
"mso-spacerun: yes"> </span>"World""</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">The first and last " characters wrap the whole lot into one parameter
passed to</font> <code><span style="font-size: 10pt">echo</span></code>
<font face="Times New Roman" size="3">so that the spacing between the two words
is kept as is. But the code:</font></p>
<pre>
<font size="2">$ echo "Hello<span style=
"mso-spacerun: yes"> </span>"World""</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">would be interpreted as three parameters:</font></p>
<ul type="disc">
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l2 level1 lfo5">
<font face="Times New Roman" size="3">"Hello "</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l2 level1 lfo5">
<font face="Times New Roman" size="3">World</font></li>
<li class="MsoNormal" style=
"margin: 0in 0in 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; tab-stops: list .5in; mso-list: l2 level1 lfo5">
<font face="Times New Roman" size="3">""</font></li>
</ul>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">So the output would be</font></p>
<pre>
<font size="2">Hello<span style="mso-spacerun: yes"> </span>World</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Note that we lose the quotes entirely. This is because the first and
second quotes mark off the Hello and following spaces; the second argument is
an unquoted "World" and the third argument is the empty string; "".</font></p>
<p><font face="Times New Roman" size="3">Most characters
(</font><code><span style="font-size: 10pt">*</span></code><font face=
"Times New Roman" size="3">,</font> <code><span style=
"font-size: 10pt">'</span></code><font face="Times New Roman" size="3">, etc)
are not interpreted (ie, they are taken literally) by means of placing them in
double quotes ("). They are taken as is and passed on the the command being
called. An example using the asterisk (*) goes:</font></p>
<pre>
<font size="2">$ echo *</font>
</pre>
<pre>
<font size="2">case.shtml escape.shtml first.shtml </font>
</pre>
<pre>
<font size="2">functions.shtml hints.shtml index.shtml </font>
</pre>
<pre>
<font size="2">ip-primer.txt raid1+0.txt</font>
</pre>
<pre>
<font size="2">$ echo *txt</font>
</pre>
<pre>
<font size="2">ip-primer.txt raid1+0.txt</font>
</pre>
<pre>
<font size="2">$ echo "*"</font>
</pre>
<pre>
<font size="2">*</font>
</pre>
<pre>
<font size="2">$ echo "*txt"</font>
</pre>
<pre>
<font size="2">*txt</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">In the first example, * is expanded to mean all files in the current
directory.<br>
In the second example, *txt means all files ending in</font> <code><span style=
"font-size: 10pt">txt</span></code><font face="Times New Roman" size="3">.<br>
In the third, we put the * in double quotes, and it is interpreted
literally.<br>
In the fourth example, the same applies, but we have appended</font>
<code><span style="font-size: 10pt">txt</span></code> <font face=
"Times New Roman" size="3">to the string.</font></p>
<p><font face="Times New Roman" size="3">However,</font> <code><span style=
"font-size: 10pt">", $, `, and</span></code> <font face="Times New Roman" size=
"3">are still interpreted by the shell, even when they're in double quotes.<br>
The backslash () character is used to mark these special characters so that
they are not interpreted by the shell, but passed on to the command being run
(for example,</font> <code><span style=
"font-size: 10pt">echo</span></code><font face="Times New Roman" size=
"3">).<br>
So to output the string: (Assuming that the value of</font> <code><span style=
"font-size: 10pt">$X</span></code> <font face="Times New Roman" size="3">is
5):</font></p>
<pre>
<font size="2">A quote is ", backslash is , backtick is `.</font>
</pre>
<pre>
<font size="2">A few spaces are<span style=
"mso-spacerun: yes"> </span>and dollar is $. $X is 5.</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">we would have to write:</font></p>
<pre>
<font size="2">$ echo "A quote is ", backslash is , backtick is `."</font>
</pre>
<pre>
<font size="2">A quote is ", backslash is , backtick is `.</font>
</pre>
<pre>
<font size="2">$ echo "A few spaces are<span style=
"mso-spacerun: yes"> </span>; dollar is $. $X is ${X}."</font>
</pre>
<pre>
<font size="2">A few spaces are<span style=
"mso-spacerun: yes"> </span>; dollar is $. $X is 5.</font>
</pre>
<p><font face="Times New Roman" size="3">We have seen why the " is special for
preserving spacing. Dollar is special because it marks a variable, so</font>
<code><span style="font-size: 10pt">$X</span></code> <font face=
"Times New Roman" size="3">is replaced by the shell with the contents of the
variable</font> <code><span style="font-size: 10pt">X</span></code><font face=
"Times New Roman" size="3">. Backslash is special because it is itself used to
mark other characters off; we need the following options for a complete
shell:</font></p>
<pre>
<font size="2">$ echo "This is a backslash"</font>
</pre>
<pre>
<font size="2">This is a backslash</font>
</pre>
<pre>
<font size="2">$ echo "This is " a quote and this is a backslash"</font>
</pre>
<pre>
<font size="2">This is " a quote and this is a backslash</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">So backslash itself must be escaped to show that it is to be taken
literally. The other special character, the backtick, is discussed later
in</font> <a href="http://steve-parker.org/sh/external.shtml"><font face=
"Times New Roman" size="3">External Programs</font></a><font face=
"Times New Roman" size="3">.</font></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt"></p>
<h2 style="margin: 12pt 0in 3pt"><em>Loops</em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Most languages have the concept of loops: If we want to repeat a task
twenty times, we don't want to have to type in the code twenty times, with
maybe a slight change each time.<br>
As a result, we have</font> <code><span style=
"font-size: 10pt">for</span></code> <font face="Times New Roman" size=
"3">and</font> <code><span style="font-size: 10pt">while</span></code>
<font face="Times New Roman" size="3">loops in the Bourne shell. This is
somewhat fewer features than other languages, but nobody claimed that shell
programming has the power of C.</font> <a name="for"></a></p>
<h3 style="margin: auto 0in"><font face="Times New Roman">For Loops</font></h3>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><code><span style=
"font-size: 10pt">for</span></code> <font face="Times New Roman" size="3">loops
iterate through a set of values until the list is exhausted:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/for.sh.txt"><font face="Times New Roman" size=
"3">for.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">for i in 1 2 3 4 5</font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "Looping ... number $i"</font>
</pre>
<pre>
<font size="2">done</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Try this code and see what it does. Note that the values can be
anything at all:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/for2.sh.txt"><font face="Times New Roman" size=
"3">for2.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">for i in hello 1 * 2 goodbye </font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "Looping ... i is set to $i"</font>
</pre>
<pre>
<font size="2">done</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">is well worth trying. Make sure that you understand what is happening
here. Try it without the</font> <code><span style=
"font-size: 10pt">*</span></code> <font face="Times New Roman" size="3">and
grasp the idea, then re-read the</font> <a href=
"http://steve-parker.org/sh/wildcards.shtml"><font face="Times New Roman" size=
"3">Wildcards</font></a> <font face="Times New Roman" size="3">section and try
it again with the</font> <code><span style="font-size: 10pt">*</span></code>
<font face="Times New Roman" size="3">in place. Try it also in different
directories, and with the</font> <code><span style=
"font-size: 10pt">*</span></code> <font face="Times New Roman" size=
"3">surrounded by double quotes, and try it preceded by a backslash
(</font><code><span style="font-size: 10pt">*</span></code><font face=
"Times New Roman" size="3">)</font></p>
<p><font face="Times New Roman" size="3">In case you don't have access to a
shell at the moment (it is very useful to have a shell to hand whilst reading
this tutorial), the results of the above two scripts are:</font></p>
<pre>
<font size="2">Looping .... number 1</font>
</pre>
<pre>
<font size="2">Looping .... number 2</font>
</pre>
<pre>
<font size="2">Looping .... number 3</font>
</pre>
<pre>
<font size="2">Looping .... number 4</font>
</pre>
<pre>
<font size="2">Looping .... number 5</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">and, for the second example:</font></p>
<pre>
<font size="2">Looping ... i is set to hello</font>
</pre>
<pre>
<font size="2">Looping ... i is set to 1</font>
</pre>
<pre>
<font size=
"2">Looping ... i is set to (name of first file in current directory)</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span>... etc ...</font>
</pre>
<pre>
<font size=
"2">Looping ... i is set to (name of last file in current directory)</font>
</pre>
<pre>
<font size="2">Looping ... i is set to 2</font>
</pre>
<pre>
<font size="2">Looping ... i is set to goodbye</font>
</pre>
<p><font face="Times New Roman" size="3">So, as you can see,</font>
<code><span style="font-size: 10pt">for</span></code> <font face=
"Times New Roman" size="3">simply loops through whatever input it is given,
until it runs out of input.</font> <a name="while"></a></p>
<h2 style="margin: 12pt 0in 3pt"><span style="mso-bookmark: while"><em>While
Loops</em></span></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><span style=
"mso-bookmark: while"><code><span style="font-size: 10pt">while</span></code>
<font face="Times New Roman" size="3">loops can be much more fun! (depending on
your idea of fun, and how often you get out of the house... )</font></span></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/while.sh.txt"><font face="Times New Roman" size=
"3">while.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">INPUT_STRING=hello</font>
</pre>
<pre>
<font size="2">while [ "$INPUT_STRING" != "bye" ]</font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "Please type something in (bye to quit)"</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>read INPUT_STRING</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "You typed: $INPUT_STRING"</font>
</pre>
<pre>
<font size="2">done</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">What happens here, is that the echo and read statements will run
indefinitely until you type "bye" when prompted.<br>
Review</font> <a href="http://steve-parker.org/sh/variables1.shtml"><font face=
"Times New Roman" size="3">Variables - Part I</font></a> <font face=
"Times New Roman" size="3">to see why we set</font> <code><span style=
"font-size: 10pt">INPUT_STRING=hello</span></code> <font face="Times New Roman"
size="3">before testing it. This makes it a repeat loop, not a traditional
while loop.</font></p>
<p><font face="Times New Roman" size="3">The colon (</font><code><span style=
"font-size: 10pt">:</span></code><font face="Times New Roman" size="3">) always
evaluates to true; whilst using this can be necessary sometimes, it is often
preferrable to use a real exit condition. Compare quitting the above loop with
the one below; see which is the more elegant. Also think of some situations in
which each one would be more useful than the other:</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/while2.sh.txt"><font face="Times New Roman"
size="3">while2.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">while :</font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "Please type something in (^C to quit)"</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>read INPUT_STRING</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "You typed: $INPUT_STRING"</font>
</pre>
<pre>
<font size="2">done</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Another useful trick is the</font> <code><span style=
"font-size: 10pt">while read f</span></code> <font face="Times New Roman" size=
"3">loop. This example uses the</font> <a href=
"http://steve-parker.org/sh/case.shtml"><font face="Times New Roman" size=
"3">case</font></a> <font face="Times New Roman" size="3">statement, which
we'll cover later. It reads from the file</font> <code><span style=
"font-size: 10pt">myfile</span></code><font face="Times New Roman" size="3">,
and for each line, tells you what language it thinks is being used. Each line
must end with a LF (newline) - if</font> <code><span style=
"font-size: 10pt">cat myfile</span></code> <font face="Times New Roman" size=
"3">doesn't end with a blank line, that final line will not be
processed.</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/while3a.sh.txt"><font face="Times New Roman"
size="3">while3a.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">while read f</font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span>case $f in</font>
</pre>
<pre>
<font size="2"><span style=
"mso-tab-count: 1"> </span>hello)<span style=
"mso-tab-count: 2"> </span>echo English<span style=
"mso-tab-count: 1"> </span>;;</font>
</pre>
<pre>
<font size="2"><span style=
"mso-tab-count: 1"> </span>howdy)<span style=
"mso-tab-count: 2"> </span>echo American<span style=
"mso-tab-count: 1"> </span>;;</font>
</pre>
<pre>
<font size="2"><span style=
"mso-tab-count: 1"> </span>gday)<span style=
"mso-tab-count: 2"> </span>echo Australian<span style=
"mso-tab-count: 1"> </span>;;</font>
</pre>
<pre>
<font size="2"><span style=
"mso-tab-count: 1"> </span>bonjour)<span style=
"mso-tab-count: 1"> </span>echo French<span style=
"mso-tab-count: 1"> </span>;;</font>
</pre>
<pre>
<font size="2"><span style=
"mso-tab-count: 1"> </span>"guten tag")<span style=
"mso-tab-count: 1"> </span>echo German<span style=
"mso-tab-count: 1"> </span>;;</font>
</pre>
<pre>
<font size="2"><span style="mso-tab-count: 1"> </span>*)<span style=
"mso-tab-count: 2"> </span>echo Unknown Language: $f</font>
</pre>
<pre>
<font size="2"><span style=
"mso-tab-count: 2"> </span>;;</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span>esac</font>
</pre>
<pre>
<font size="2">done < myfile</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">On many Unix systems, this can be also be done as</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/while3b.sh.txt"><font face="Times New Roman"
size="3">while3b.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">while f=`line`</font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span>.. process f ..</font>
</pre>
<pre>
<font size="2">done < myfile</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">But since the</font> <code><span style="font-size: 10pt">while read
f</span></code> <font face="Times New Roman" size="3">works with any *nix, and
doesn't depend on the external program</font> <code><span style=
"font-size: 10pt">line</span></code><font face="Times New Roman" size="3">, the
former is preferable. See</font> <a href=
"http://steve-parker.org/sh/external.shtml"><font face="Times New Roman" size=
"3">External Programs</font></a> <font face="Times New Roman" size="3">to see
why this method uses the backtick (`).<br>
Had I referred to</font> <code><span style="font-size: 10pt">$i</span></code>
<font face="Times New Roman" size="3">(not</font> <code><span style=
"font-size: 10pt">$f</span></code><font face="Times New Roman" size="3">) in
the default ("Unknown Language") case above - you will get no warnings or
errors in this case, even though</font> <code><span style=
"font-size: 10pt">$i</span></code> <font face="Times New Roman" size="3">has
not been declared or defined. For example:</font></p>
<pre>
<font size="2">$ i=THIS_IS_A_BUG</font>
</pre>
<pre>
<font size="2">$ export i</font>
</pre>
<pre>
<font size="2">$ ./while3.sh something</font>
</pre>
<pre>
<font size="2">Unknown Language: THIS_IS_A_BUG</font>
</pre>
<pre>
<font size="2">$</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">So make sure that you avoid typos. This is also another good reason
for using</font> <code><span style="font-size: 10pt">${x}</span></code>
<font face="Times New Roman" size="3">and not just</font> <code><span style=
"font-size: 10pt">$x</span></code> <font face="Times New Roman" size="3">-
if</font> <code><span style="font-size: 10pt">x="A"</span></code> <font face=
"Times New Roman" size="3">and you want to say "A1", you need</font>
<code><span style="font-size: 10pt">echo ${x}1</span></code><font face=
"Times New Roman" size="3">, as</font> <code><span style="font-size: 10pt">echo
$x1</span></code> <font face="Times New Roman" size="3">will try to use the
variable</font> <code><span style="font-size: 10pt">x1</span></code><font face=
"Times New Roman" size="3">, which may not exist, or may be set to</font>
<code><span style="font-size: 10pt">B2</span></code><font face=
"Times New Roman" size="3">.</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">I recently found an old thread on Usenet which I had been involved in,
where I actually learned more ...</font> <a href=
"http://groups.google.com/groups?hl=en&safe=off&selm=D9I1pp.JM%40info.bris.ac.uk">
<font face="Times New Roman" size="3">Google has it here.</font></a><font face=
"Times New Roman" size="3">.</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">A handy Bash (but not Bourne Shell) tip I learned recently from
the</font> <a href="http://www.linuxfromscratch.org/"><font face=
"Times New Roman" size="3">Linux From Scratch</font></a> <font face=
"Times New Roman" size="3">project is:</font></p>
<pre>
<font size="2">mkdir rc{0,1,2,3,4,5,6,S}.d</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">instead of the more cumbersome:</font></p>
<pre>
<font size="2">for runlevel in 0 1 2 3 4 5 6 S</font>
</pre>
<pre>
<font size="2">do</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>mkdir rc${runlevel}.d</font>
</pre>
<pre>
<font size="2">done</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">And this can be done recursively, too:</font></p>
<pre>
<font size="2">$ cd /</font>
</pre>
<pre>
<font size="2">$ ls -ld {,usr,usr/local}/{bin,sbin,lib}</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>2 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>4096 Oct 26 01:00 /bin</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>6 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>4096 Jan 16 17:09 /lib</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>2 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>4096 Oct 27 00:02 /sbin</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>2 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>40960 Jan 16 19:35 usr/bin</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>83 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>49152 Jan 16 17:23 usr/lib</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>2 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>4096 Jan 16 22:22 usr/local/bin</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>3 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>4096 Jan 16 19:17 usr/local/lib</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>2 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span><span style=
"mso-spacerun: yes"> </span>4096 Dec 28 00:44 usr/local/sbin</font>
</pre>
<pre>
<font size="2">drwxr-xr-x<span style=
"mso-spacerun: yes"> </span>2 root<span style=
"mso-spacerun: yes"> </span>root<span style=
"mso-spacerun: yes"> </span>8192 Dec 27 02:10 usr/sbin</font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<h1 style="margin: 12pt 0in 3pt"><font size="5">We will use while loops further
in the</font> <a href="http://steve-parker.org/sh/test.shtml"><font size=
"5">Test</font></a> <font size="5">and</font> <a href=
"http://steve-parker.org/sh/case.shtml"><font size="5">Case</font></a>
<font size="5">sections. Test</font></h1>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Test is used by virtually every shell script written. It may not seem
that way, because</font> <code><span style="font-size: 10pt">test</span></code>
<font face="Times New Roman" size="3">is not often called directly.</font>
<code><span style="font-size: 10pt">test</span></code> <font face=
"Times New Roman" size="3">is more frequently called as</font>
<code><span style="font-size: 10pt">[</span></code><font face="Times New Roman"
size="3">.</font> <code><span style="font-size: 10pt">[</span></code>
<font face="Times New Roman" size="3">is a symbolic link to test, just to make
shell programs more readable. If is also normally a shell builtin (which means
that the shell itself will interpret [ as meaning test, even if your Unix
environment is set up differently):</font></p>
<pre>
<font size="2">$ type [</font>
</pre>
<pre>
<font size="2">[ is a shell builtin</font>
</pre>
<pre>
<font size="2">$ which [</font>
</pre>
<pre>
<font size="2">/usr/bin/[</font>
</pre>
<pre>
<font size="2">$ ls -l /usr/bin/[</font>
</pre>
<pre>
<font size=
"2">lrwxrwxrwx 1 root root 4 Mar 27 2000 /usr/bin/[ -> test</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This means that '[' is actually a program, just like</font>
<code><span style="font-size: 10pt">ls</span></code> <font face=
"Times New Roman" size="3">and other programs, so it must be surrounded by
spaces:</font></p>
<pre>
<font size="2">if [$foo == "bar" ]</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">will not work; it is interpreted as</font> <code><span style=
"font-size: 10pt">if test$foo == "bar" ]</span></code><font face=
"Times New Roman" size="3">, which is a ']' without a beginning '['. Put spaces
around all your operators I've highlighted the mandatory spaces with the word
'SPACE' - replace 'SPACE' with an actual space; if there isn't a space there,
it won't work:</font></p>
<pre>
<font size="2">if SPACE [ SPACE "$foo" SPACE == SPACE "bar" SPACE ]</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><br>
<font face="Times New Roman" size="3">Test is a simple but powerful comparison
utility. For full details, run</font> <code><span style="font-size: 10pt">man
test</span></code> <font face="Times New Roman" size="3">on your system, but
here are some usages and typical examples.</font></p>
<p><font face="Times New Roman" size="3">Test is most often invoked indirectly
via the</font> <code><span style="font-size: 10pt">if</span></code> <font face=
"Times New Roman" size="3">and</font> <code><span style=
"font-size: 10pt">while</span></code> <font face="Times New Roman" size=
"3">statements. It is also the reason you will come into difficulties if you
create a program called</font> <code><span style=
"font-size: 10pt">test</span></code> <font face="Times New Roman" size="3">and
try to run it, as this shell builtin will be called instead of your
program!<br>
The syntax for</font> <code><span style=
"font-size: 10pt">if...then...else...</span></code> <font face=
"Times New Roman" size="3">is:</font></p>
<pre>
<font size="2">if [ ... ]</font>
</pre>
<pre>
<font size="2">then</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span># if-code</font>
</pre>
<pre>
<font size="2">else</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span># else-code</font>
</pre>
<pre>
<font size="2">fi</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Note that</font> <code><span style="font-size: 10pt">fi</span></code>
<font face="Times New Roman" size="3">is</font> <code><span style=
"font-size: 10pt">if</span></code> <font face="Times New Roman" size=
"3">backwards! This is used again later with</font> <a href=
"http://steve-parker.org/sh/case.shtml"><font face="Times New Roman" size=
"3">case</font></a> <font face="Times New Roman" size="3">and</font>
<code><span style="font-size: 10pt">esac</span></code><font face=
"Times New Roman" size="3">.<br>
Also, be aware of the syntax - the "if [ ... ]" and the "then" commands must be
on different lines. Alternatively, the semicolon ";" can seperate
them:</font></p>
<pre>
<font size="2">if [ ... ]; then</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span># do something</font>
</pre>
<pre>
<font size="2">fi</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">You can also use the</font> <code><span style=
"font-size: 10pt">elif</span></code><font face="Times New Roman" size="3">,
like this:</font></p>
<pre>
<font size="2">if<span style=
"mso-spacerun: yes"> </span>[ something ]; then</font>
</pre>
<pre>
<font size="2"> echo "Something"</font>
</pre>
<pre>
<font size="2"> elif [ something_else ]; then</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "Something else"</font>
</pre>
<pre>
<font size="2"> else</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "None of the above"</font>
</pre>
<pre>
<font size="2">fi</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This will echo "Something" if the</font> <code><span style=
"font-size: 10pt">[ something ]</span></code> <font face="Times New Roman"
size="3">test succeeds, otherwise it will test</font> <code><span style=
"font-size: 10pt">[ something_else ]</span></code><font face="Times New Roman"
size="3">, and echo "Something else" if that succeeds. If all else fails, it
will echo "None of the above".</font></p>
<p><font face="Times New Roman" size="3">Try the following code snippet, before
running it set the variable X to various values (try -1, 0, 1, hello, bye,
etc). You can do this as follows (thanks to Dave for pointing out the need to
export the variable, as noted in</font> <a href=
"http://steve-parker.org/sh/variables1.shtml"><font face="Times New Roman"
size="3">Variables - Part I</font></a><font face="Times New Roman" size=
"3">.):</font></p>
<pre>
<font size="2">$ X=5</font>
</pre>
<pre>
<font size="2">$ export X</font>
</pre>
<pre>
<font size="2">$ ./test.sh</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>... output of test.sh ...</font>
</pre>
<pre>
<font size="2">$ X=hello</font>
</pre>
<pre>
<font size="2">$ ./test.sh</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>... output of test.sh ...</font>
</pre>
<pre>
<font size="2">$ X=test.sh</font>
</pre>
<pre>
<font size="2">$ ./test.sh</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>... output of test.sh ...</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Then try it again, with</font> <code><span style=
"font-size: 10pt">$X</span></code> <font face="Times New Roman" size="3">as the
name of an existing file, such as</font> <code><span style=
"font-size: 10pt">/etc/hosts</span></code><font face="Times New Roman" size=
"3">.</font></p>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"http://steve-parker.org/sh/eg/test.sh.txt"><font face="Times New Roman" size=
"3">test.sh</font></a></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size="2">if [ "$X" -lt "0" ]</font>
</pre>
<pre>
<font size="2">then</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is less than zero"</font>
</pre>
<pre>
<font size="2">fi</font>
</pre>
<pre>
<font size="2">if [ "$X" -gt "0" ]; then</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is more than zero"</font>
</pre>
<pre>
<font size="2">fi</font>
</pre>
<pre>
<font size="2">[ "$X" -le "0" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is less than or equal to<span style=
"mso-spacerun: yes"> </span>zero"</font>
</pre>
<pre>
<font size="2">[ "$X" -ge "0" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is more than or equal to zero"</font>
</pre>
<pre>
<font size="2">[ "$X" = "0" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is the string or number "0""</font>
</pre>
<pre>
<font size="2">[ "$X" = "hello" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X matches the string "hello""</font>
</pre>
<pre>
<font size="2">[ "$X" != "hello" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is not the string "hello""</font>
</pre>
<pre>
<font size="2">[ -n "$X" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is of nonzero length"</font>
</pre>
<pre>
<font size="2">[ -f "$X" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is the path of a real file" || </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "No such file: $X"</font>
</pre>
<pre>
<font size="2">[ -x "$X" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is the path of an executable file"</font>
</pre>
<pre>
<font size="2">[ "$X" -nt "/etc/passwd" ] && </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is a file which is newer than /etc/passwd" </font>
</pre>
<div class="MsoNormal" style="margin: 0in 0in 0pt">
<hr align="left" width="40%" color="#ACA899" noshade="noshade" size="2"></div>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">Note that we can use the semicolon (;) to join two lines together.
This is often done to save a bit of space in simple</font> <code><span style=
"font-size: 10pt">if</span></code> <font face="Times New Roman" size=
"3">statements. The backslash simply tells the shell that this is not the end
of the line, but the two (or more) lines should be treated as one. This is
useful for readability. It is customary to indent the following
line.</font></p>
<p><font face="Times New Roman" size="3">As we see from these examples,</font>
<code><span style="font-size: 10pt">test</span></code> <font face=
"Times New Roman" size="3">can perform many tests on numbers, strings, and
filenames.</font></p>
<p><font face="Times New Roman" size="3">There is a simpler way of
writing</font> <code><span style="font-size: 10pt">if</span></code> <font face=
"Times New Roman" size="3">statements: The</font> <code><span style=
"font-size: 10pt">&&</span></code> <font face="Times New Roman" size=
"3">and</font> <code><span style="font-size: 10pt">||</span></code> <font face=
"Times New Roman" size="3">commands give code to run if the result is
true.</font></p>
<pre>
<font size="2">#!/bin/sh</font>
</pre>
<pre>
<font size=
"2">[ $X -ne 0 ] && echo "X isn't zero" || echo "X is zero"</font>
</pre>
<pre>
<font size=
"2">[ -f $X ] && echo "X is a file" || echo "X is not a file"</font>
</pre>
<pre>
<font size="2">[ -n $X ] && echo "X is of non-zero length" || </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "X is of zero length"</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This syntax is possible because there is a file (or shell-builtin)
called</font> <code><span style="font-size: 10pt">[</span></code> <font face=
"Times New Roman" size="3">which is linked to</font> <code><span style=
"font-size: 10pt">test</span></code><font face="Times New Roman" size="3">. Be
careful using this construct, though, as overuse can lead to very hard-to-read
code. The</font> <code><span style=
"font-size: 10pt">if...then...else...</span></code> <font face=
"Times New Roman" size="3">structure is much more readable. Use of the</font>
<code><span style="font-size: 10pt">[...]</span></code> <font face=
"Times New Roman" size="3">construct is recommended for while loops and trivial
sanity checks with which you do not want to overly distract the
reader.</font></p>
<p><font face="Times New Roman" size="3">Note that when you set X to a
non-numeric value, the first few comparisons result in the message:</font></p>
<pre>
<font size="2">test.sh: [: integer expression expected before -lt</font>
</pre>
<pre>
<font size="2">test.sh: [: integer expression expected before -gt</font>
</pre>
<pre>
<font size="2">test.sh: [: integer expression expected before -le</font>
</pre>
<pre>
<font size="2">test.sh: [: integer expression expected before -ge</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">This is because the -lt, -gt, -le, -ge, comparisons are only designed
for integers, and do not work on strings. The string comparisons, such
as</font> <code><span style="font-size: 10pt">!=</span></code> <font face=
"Times New Roman" size="3">will happily treat "5" as a string, but there is no
sensible way of treating "Hello" as an integer, so the integer comparisons
complain.<br>
If you want your shell script to behave more gracefully, you will have to check
the contents of the variable before you test it - maybe something like
this:</font></p>
<pre>
<font size="2">echo $X | grep [^0-9] > /dev/null 2>&1</font>
</pre>
<pre>
<font size="2">if [ "$?" -eq "0" ]; then</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span># If the grep found something other than 0-9</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span># then it's not an integer.</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "Sorry, wanted a number"</font>
</pre>
<pre>
<font size="2">else</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span># The grep found only 0-9, so it's an integer. </font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span># We can safely do a test on it.</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>if [ "$X" -eq "7" ]; then</font>
</pre>
<pre>
<font size="2"><span style=
"mso-spacerun: yes"> </span>echo "You entered the magic number!"</font>
</pre>
<pre>
<font size="2"><span style="mso-spacerun: yes"> </span>fi</font>
</pre>
<pre>
<font size="2">fi</font>
</pre>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">In this way you can</font> <code><span style=
"font-size: 10pt">echo</span></code> <font face="Times New Roman" size="3">a
more meaningful message to the user, and exit gracefully. The</font>
<code><span style="font-size: 10pt">$?</span></code> <font face=
"Times New Roman" size="3">variable is explained in</font> <a href=
"http://steve-parker.org/sh/variables2.shtml"><font face="Times New Roman"
size="3">Variables - Part II</font></a><font face="Times New Roman" size="3">,
and</font> <code><span style="font-size: 10pt">grep</span></code> <font face=
"Times New Roman" size="3">is a complicated beast, so here goes:</font>
<code><span style="font-size: 10pt">grep [0-9]</span></code> <font face=
"Times New Roman" size="3">finds lines of text which contain digits (0-9) and
possibly other characters, so the carat (</font><code><span style=
"font-size: 10pt">^</span></code><font face="Times New Roman" size="3">)
in</font> <code><span style="font-size: 10pt">grep [^0-9]</span></code>
<font face="Times New Roman" size="3">finds only those lines which don't
consist only of numbers. We can then take the opposite (by acting on failure,
not success). Okay? The</font> <code><span style=
"font-size: 10pt">>/dev/null 2>&1</span></code> <font face=
"Times New Roman" size="3">directs any output or errors to the special "null"
device, instead of going to the user's screen.<br>
Many thanks to Paul Schermerhorn for correcting me - this page used to claim
that</font> <code><span style="font-size: 10pt">grep -v [0-9]</span></code></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><font face="Times New Roman"
size="3">would work, but this is clearly far too simplistic.</font></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt"></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt"><a href=
"/page/BOURNE%20SHELL%20CONTINUE...%20">next>></a></p>