-CONTINUED
If you find that you are uncomfortable with the format
of the if and test structure,
that is:
if test -f /etc/foo
then
then, you can do it like this:
if [ -f /etc/foo ]; then
The square brackets form test . If you have
experience in C programming, this syntax might be more comfortable.
Notice that there has to be white space surrounding both
square brackets. The semicolon: "; " tells the
shell that this is the end of the command. Anything after
the semicolon will be run as though it is on a separate
line. This makes it easier to read basically, and is of
course, optional. If you prefer, just put then
on the next line.
When using variables with test , it is a good
idea to have them surrounded with quotation marks. Example:
if [ "$name" -eq 5 ]; then
while ... do ... done
The while structure is a looping structure.
Basically what it does is, "while this condition is true,
do this until the condition is no longer true". Let us look
at an example:
#!/bin/bash
while true; do
echo "Press CTRL-C to quit."
done
true is actually a program. What this program
does is continuously loop over and over without stopping.
Using true is considered to be slow because
your shell program has to call it up first and then run
it. You can use an alternative, the ": " command:
#!/bin/bash
while :; do
echo "Press CTRL-C to quit."
done
This achieves the exact same thing, but is faster because
it is a built in feature in bash . The only
difference is you sacrifice readability for speed. Use whichever
one you feel more comfortable with. Here is perhaps, a much
more useful example, using variables:
#!/bin/bash
x=0; # initialize x to 0
while [ "$x" -le 10 ]; do
echo "Current value of x: $x"
# increment the value of x:
x=$(expr $x + 1)
sleep 1
done
As you can see, we are making use of the test
(in its square bracket form) here to check the condition
of the variable x . The option -le
checks to see if x is less than, or equal to
the value 10. In English, the code above says, "While x
is less than 10 or equal to 10, print the current value
of x, and then add 1 to the current value of x.". sleep
1 is just to get the program to pause for one second.
You can remove it if you want. As you can see, what we were
doing here was testing for equality. Check if a variable
equals a certain value, and if it does, act accordingly.
Here is a list of equality tests:
Checks equality between numbers:
x -eq y Check is x
is equals to y
x -ne y Check if x
is not equals to y
x -gt y Check ifx
is greater than y
x -lt y Check if x
is less than y
Checks equality between strings:
x = y Check if x
is the same as y
x != y Check if x
is not the same as y
-n x Evaluates to true if x
is not null
-z x Evaluates to true if x
is null.
The above looping script we wrote should not be hard to
understand, except maybe for this line:
x=$(expr $x + 1)
The comment above it tells us that it increments x
by 1. But what does $(...) mean? Is it a variable?
No. In fact, it is a way of telling the shell that you want
to run the command expr $x + 1 , and assign
its result to x . Any command enclosed in $(...)
will be run:
#!/bin/bash
me=$(whoami)
echo "I am $me."
Try it and you will understand what I mean. The above
code could have been written as follows with equivalent
results:
#!/bin/bash
echo "I am $(whoami)."
You decide which one is easier for you to read. There
is another way to run commands or to give variables the
result of a command. This will be explained later on. For
now, use $(...) .
until ... do ... done
The until structure is very similar to the
while structure. The only difference is that
the condition is reversed. The while structure
loops while the condition is true. The until
structure loops until the condition is true. So basically
it is "until this condition is true, do this". Here is an
example:
#!/bin/bash
x=0
until [ "$x" -ge 10 ]; then
echo "Current value of x: $x"
x=$(expr $x + 1)
sleep 1
done
This piece of code may look familiar. Try it out and see
what it does. Basically, until will continue
looping until x is either greater than, or
equal to 10. When it reaches the value 10, the loop will
stop. Therefore, the last value printed for x
will be 9.
for ... in ... do ... done
The for structure is used when you are looping
through a range of variables. For instance, you can write
up a small program that prints 10 dots each second:
#!/bin/bash
echo -n "Checking system for errors"
for dots in 1 2 3 4 5 6 7 8 9 10; do
echo -n "."
echo "System clean."
done
In case you do not know, the -n option to
echo prevents a new line from automatically
being added. Try it once with the -n option,
and then once without to see what I mean. The variable dots
loops through values 1 to 10, and prints a dot at each value.
Try this example to see what I mean by the variable looping
through the values:
#!/bin/bash
for x in paper pencil pen; do
echo "The value of variable x is: $x"
sleep 1
done
When you run the program, you see that x
will first hold the value paper , and then it
will go to the next value, pencil , and then
to the next value, pen . When it finds no more
values, the loop ends.
Here is a much more useful example. The following program
adds a .html extension to all files in the
current directory:
#!/bin/bash
for file in *; do
echo "Adding .html extension to $file..."
mv $file $file.html
sleep 1
done
If you do not know, * is a wild card character.
It means, "everything in the current directory", which is
in this case, all the files in the current directory. All
files in the current directory are then given a .html
extension. Recall that variable file will loop
through all the values, in this case, the files in the current
directory. mv is then used to rename the value
of variable file with a .html
extension.
case ... in ... done
The case structure is very similar to the if
structure. Basically it is great for times where there are
a lot of conditions to be checked, and you do not want to
have to use if over and over again. Take the
following piece of code:
#!/bin/bash
x=5 # initialize x to 5
# now check the value of x:
case $x in
0) echo "Value of x is 0."
;;
5) echo "Value of x is 5."
;;
9) echo "Value of x is 9."
;;
*) echo "Unrecognized value."
esac
The case structure will check check the value
of x against 3 possibilities. In this case,
it will first check if x has the value of 0,
and then check if the value is 5, and then check if the
value is 9. Finally, if all the checks fail, it will produce
a message, "Unrecognized value.". Remember that "* "
means "everything", and in this case, "any other value other
than what was specified". If x holds any other
value other than 0, 5, or 9, then this value falls into
the * 's category. When using case ,
each condition must be ended with two semicolons. Why bother
using case when you can use if ?
Here is the equivalent program, written with if .
See which one is faster to write, and easier to read:
#!/bin/bash
x=5 # initialize x to 5
if [ "$x" -eq 0 ]; then
echo "Value of x is 0."
elif [ "$x" -eq 5 ]; then
echo "Value of x is 5."
elif [ "$x" -eq 9 ]; then
echo "Value of x is 9."
else
echo "Unrecognized value."
fi
QUOTATIONS
Quotation marks play a big part in shell scripting. There
are three types of quotation marks. They are the double
quote: " , the forward quote: ' ,
and the back quote: ` . Does each of them mean
something? Yes.
The double quote is used mainly to hold a string of words
and preserve whitespace. For instance, "This string contains
whitespace.". A string enclosed in double quotes is treated
as one argument. For instance, take the following
examples:
xconsole$
mkdir hello world
xconsole$ ls -F
hello/ world/
Here we created two directories. mkdir took
the strings hello and world as
two arguments, and thus created two directories. Now, what
happens when you do this:
xconsole$
mkdir "hello world"
xconsole$ ls -F
hello/ hello world/ world/
It created a directory with two words. The quotation marks
made two words, into one argument. Without the quotation
marks, mkdir would think that hello
was the first argument, and world , the second.
Forward quotes are used primarily to deal with variables.
If a variable is enclosed in double quotes, its value will
be evaluated. If it is enclosed in forward quotes, its value
will not be evaluated. To make this clearer, try the following
example:
#!/bin/bash
x=5 # initialize x to 5
# use double quotes
echo "Using double quotes, the value of x is: $x"
# use forward quotes
echo 'Using forward quotes, the value of x is: $x'
See the difference? You can use double quotes if you do
not plan on using variables for the string you wish to enclose.
In case you are wondering, yes, forward quotes can be used
to preserve whitespace just like double quotes:
xconsole$
mkdir 'hello world'
xconsole$ ls -F
hello world/
Back quotes are completely different from double and forward
quotes. They are not used to preserve whitespace. If you
recall, earlier on, we used this line:
x=$(expr $x + 1)
As you already know, the result of the command expr
$x + 1 is assigned to variable x . The
exact same result can be achieved with back quotes:
x=`expr $x + 1`
Which one should you use? Whichever one you prefer. You
will find the back quote used more often than the $(...) .
However, I find $(...) easier to read, especially
if you have something like this:
$!/bin/bash
echo "I am `whoami`"
|