Armed with expressions, let's look at our first decision-making process.
Remember in our eatout.sh script, we wanted to test whether the user has started eatout.sh with the correct number of parameters. So let's start by adding that functionality to that script.
How do we add if statements? An if statement has the following form:
if condition then do some operations fi |
Now, since I'm lecturing you, I might as well lecture you in good structured programming style.
When you start an 'IF' statement, put the 'THEN' statement on the next line, and make sure that you indent all the commands that you want within the 'THEN', by at least one tab or a couple of spaces. Finally, end your "IF" statement in a nice block format using the 'FI'. It's going to make maintaining your scripts much easier.
In our eatout.sh
if [ "$#" -lt 1 ] then echo "Usage: $0 <parameter> echo "where parameter is: italian|thai|smart|steakhouse" exit 1 fi |
If we add this to the top of eatout.sh, our script will stop running if the user does not provide at least one positional parameter, or argument. Furthermore it will echo the usage command to explain how to use the script correctly and to avoid the error message.
Equally, 'IF' has an associated construct, the 'ELSE':
if condition then ... <condition was TRUE, do these actions> ... else ... <condition was FALSE, do these actions> ... fi |
If a user runs the eatout.sh script with a correct parameter, then you can show them your favourite eating places, and if they don't it will exit with a status of 1 as well as a usage summary.
Notice that the condition that I used is a very simple one: I'm checking whether the number of parameters is less than one.
I'll leave it as an exercise for the user to check that the parameter that the user has entered is one of the allowed words (italian/steakhouse/smart).
To give you a hint, you could use:
[ $# -lt 1 -a "$1" = 'italian' or "$1" = 'steakhouse' or ..." |
So you're to check that the number of parameters is at least one AND the $1 is equal to one of the allowed words. Is there a better way of doing this? There sure is.
What we might want to do is, if the restaurant we choose is a steakhouse, we might want to allow the user to choose between 5 different ways of doing their steak. For that we're going to want to do more than one test:
if $1 steakhouse then ... ask how they like their steak done ... else if $1 smart then ... else if $1 thai then ... fi fi fi |
Note that there have to be matching fi's for every if statement.
As you can see reading this becomes quite difficult due to all the embedded if statements. There is an alternative construct called an elif which replaces the else-if with an elif and this makes the readability easier.
Look below for the syntax:
if $1 steakhouse then ... elif $1 smart then ... elif $1 thai then ... elif $1 italian then ... else .. fi |
Note that the final else is tied to the closest if. So in our example, the else statement will only be executed if $1 is NOT an italian resturant.
Is the 'IF' statement the best way of doing things? If you're going to do else if, else if, else if, etc. - then the answer is NO! It's bad programming practice to do this else-if, else-if nonsense. So how do we do things?
Well we've got a 'CASE' statement. The structure of a 'CASE' statement is as follows:
case $1 in pattern) ... ... ;; pattern) ... ... ;; *) ... ... ;; esac |
This means that we will match $1 to a pattern. The pattern will allow us to execute a series of statements and to finish this pattern we use a double semi-colon. We can then match the next pattern and, if it matches we do another whole series of things, ending with another double semi-colon.
If $1 matches none of the patterns, then it will be caught by the asterisk pattern since an a asterisk matches everything as we've seen in our regular expression and pattern theory.
The case statement makes your code a lot more legible, easier to maintain and allows you to match patterns.
Look at another example:
case $1 in [Tt][Hh][Aa][Ii]) ... ... ;; Steakhouse) ... ... ;; *) echo "Sorry this pattern does not match any restaurant" ... ;; esac |
In this CASE statement, the first pattern matches ThAI or thAI or Thai, etc.
There's a better way of making your patterns case-insensitive. You could put the following line at the top of your script which would translate every character in your parameter $1 to uppercase:
RESTURANT_TYPE=(echo $1 |tr '[a-z]' '[A-Z]') |
This will remove the long complicated pattern:
[Tt][Hh][Aa][Ii]) |
and we could instead just look for the pattern:
THAI |
Similarly, if the user of our eatout.sh script only wants to type out part of the keyword for example, using:
./eatout.sh steak |
instead of
./eatout.sh steakhouse |
or
./eatout.sh meat |
instead of
./eatout.sh steakhouse |
These choices can be matched with the following pattern
steak|steakhouse|meat |
Similarly this pattern
pasta|pizza|italian |
would match all of the following uses of our script:
eatout.sh pasta |
and
eatout.sh pizza |
and
eatout.sh italian |
So you can match ranges of alternatives separating each with a vertical bar - the pipe character. So the case statement is most certainly the far better way to match alternatives with a script.
Write a script to test whether the free disk space on your largest partition is less than 10%. If it is, print a message to the screen indicating this fact.
Modify your menu.sh written earlier in the course to allow the user to run the menu system with a parameter on the command line, producing output informing the user what option was selected on the command line. Do not use the CASE statement for this example.
Rewrite the exercise in 2 above, this time using the CASE statement. Ensure that the user can use a combination of upper and lowercase charaters in their selection.
Using the uptime from /proc/uptime, write a script which will determine how long your Linux machine has been 'UP', printing the following output to the console accoring to the results:
0 - 1 hour "Obviously you're new to Linux. What's \ all this rebooting your machine nonsense" 1 - 5 hours "Still a novice I see, but perhaps I could be wrong" 1 - 5 days "Mmmm. You're getting better at this Linux thing!" |