Thursday, October 22, 2009

The elif Construct








 

 










The elif Construct



As your programs become more complex, you may find yourself needing to write nested if statements of the following form:





if command1

then

command

command

...

else

if command2

then

command

command

...

else

...

if commandn

then

command

command

...

else

command

command

...

fi

...

fi

fi



This type of command sequence is useful when you need to make more than just a two-way decision as afforded by the if-else construct. In this case, a multiway decision is made, with the last else clause executed if none of the preceding conditions is satisfied.



As an example, suppose that you wanted to write a program called greetings that would print a friendly "Good morning," "Good afternoon," or "Good evening" whenever you logged on to the system. For purposes of the example, consider any time from midnight to noon to be the morning, noon to 6:00 p.m. the afternoon, and 6:00 p.m. to midnight the evening.



To write this program, you have to find out what time it is. date serves just fine for this purpose. Take another look at the output from this command:





$ date

Wed Aug 29 10:42:01 EDT 2002

$



The format of date's output is fixed, a fact that you can use to your advantage when writing greetings because this means that the time will always appear in character positions 12 through 19. Actually, for this program, you really only need the hour displayed in positions 12 and 13. So to get the hour from date, you can write





$ date | cut -c12-13

10

$



Now the task of writing the greetings program is straightforward:





$ cat greetings

#

# Program to print a greeting

#



hour=$(date | cut -c12-13)



if [ "$hour" -ge 0 -a "$hour" -le 11 ]

then

echo "Good morning"

else

if [ "$hour" -ge 12 -a "$hour" -le 17 ]

then

echo "Good afternoon"

else

echo "Good evening"

fi

fi

$



If hour is greater than or equal to 0 (midnight) and less than or equal to 11 (up to 11:59:59), "Good morning" is displayed. If hour is greater than or equal to 12 (noon) and less than or equal to 17 (up to 5:59:59 p.m.), "Good afternoon" is displayed. If neither of the preceding two conditions is satisfied, "Good evening" is displayed.





$ greetings

Good morning

$



As noted, the nested if command sequence used in greetings is so common that a special elif construct is available to more easily express this sequence. The general format of this construct is





if commandl

then

command

command

...

elif command2

then

command

command

...

elif commandn

then

command

command

...

else

command

command

...

fi



command1, command2, ..., commandn are executed in turn and their exit statuses tested. As soon as one returns an exit status of zero, the commands listed after the then that follows are executed up to another elif, else, or fi. If none of the commands returns a zero exit status, the commands listed after the optional else are executed.



You could rewrite the greetings program using this new format as shown:





$ cat greetings

#

# Program to print a greeting -- version 2

#



hour=$(date | cut -c12-13)



if [ "$hour" -ge 0 -a "$hour" -le 11 ]

then

echo "Good morning"

elif [ "$hour" -ge 12 -a "$hour" -le 17 ]

then

echo "Good afternoon"

else

echo "Good evening"

fi

$



This version is easier to read, and it doesn't have the tendency to disappear off the right margin due to excessive indentation. Incidentally, you should note that date provides a wide assortment of options. One of these, %H, can be used to get the hour directly from date:





$ date +%H

10

$



As an exercise, you should change greetings to make use of this fact.



Yet Another Version of rem



Another way to add some robustness to the rem program would be to check the number of entries that matched before doing the removal. If there's more than one match, you could issue a message to the effect and then terminate execution of the program. But how do you determine the number of matching entries? One approach is to do a normal grep on the phonebook file and then count the number of matches that come out with wc. If the number of matches is greater than one, the appropriate message can be issued.





$ cat rem

#

# Remove someone from the phone book -- version 3

#



if [ "$#" -ne 1 ]

then

echo "Incorrect number of arguments."

echo "Usage: rem name"

exit 1

fi



name=$1



#

# Find number of matching entries

#



matches=$(grep "$name" phonebook | wc �l)



#

# If more than one match, issue message, else remove it

#



if [ "$matches" -gt 1 ]

then

echo "More than one match; please qualify further"

elif [ "$matches" -eq 1 ]

then

grep -v "$name" phonebook > /tmp/phonebook

mv /tmp/phonebook phonebook

else

echo "I couldn't find $name in the phone book"

fi

$



The positional parameter $1 is assigned to the variable name after the number of arguments check is performed to add readability to the program. Subsequently using $name is a lot clearer than using $1.



The if...elif...else command first checks to see whether the number of matches is greater than one. If it is, the "More than one match" message is printed. If it's not, a test is made to see whether the number of matches is equal to one. If it is, the entry is removed from the phone book. If it's not, the number of matches must be zero, in which case a message is displayed to alert the user of this fact.



Note that the grep command is used twice in this program: first to determine the number of matches and then with the -v option to remove the single matching entry.



Here are some sample runs of the third version of rem:





$ rem

Incorrect number of arguments.

Usage: rem name

$ rem Susan

More than one match; please qualify further

$ rem 'Susan Topple'

$ rem 'Susan Topple'

I couldn't find Susan Topple in the phone book She's history

$



Now you have a fairly robust rem program: It checks for the correct number of arguments, printing the proper usage if the correct number isn't supplied; it also checks to make sure that precisely one entry is removed from the phonebook file.












     

     


    No comments:

    Post a Comment