DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
Programming with the UNIX system shell

Conditional constructs: if and case

Conditional constructs cause branches in the path of execution based on the outcome of a comparison.

if . . . then

The if command tells the shell program to execute the then sequence of commands only if the final command in the if command list is successful. The if construct ends with the keyword fi.

The general format for the if construct is shown in ``Format of the if . . . then conditional construct''.

   if
        command_1
            .
            .
            .
        last_command
      then
           command_1
               .
               .
               .
           last_command
   fi

Format of the if . . . then conditional construct

For example, a shell program called search demonstrates the use of the if . . . then construct. The search program uses the grep command to search for a word in a file. If grep is successful, the program echos that the word is found in the file. Copy the search program (shown on the following screen) and try it yourself:

   $ cat search
   echo Type in the word and the filename.
   read word file
   if grep $word $file
      then echo $word is in $file
   fi
   $

Notice that the read command assigns values to two variables. The first characters you type, up to a space, are assigned to word. The rest of the characters, including embedded spaces, are assigned to file.

A problem with this program is the unwanted display of output from the grep command. If you want to dispose of the system response to the grep command in your program, use the file /dev/null, changing the if command line to the following:

   if grep $word $file > /dev/null
Now execute your search program. It should respond only with the message specified after the echo command.

if . . . then . . . else

The if . . . then construction can also issue an alternate set of commands with else, when the if command sequence is false. when the if command sequence is false. It has the general format shown in ``Format of the if . . . then . . . else conditional construct''.

   if
        command_1
            .
            .
            .
        last_command
      then
           command_1
               .
               .
               .
           last_command
      else
           command_1
               .
               .
               .
           last_command
   fi

Format of the if . . . then . . . else conditional construct

You can now improve your search command so it will tell you when it cannot find a word, as well as when it can. The following screen shows how your improved program will look:

   $ cat search
   echo Type in the word and the filename.
   read word file
   if
      grep $word $file >/dev/null
   then
      echo $word is in $file
   else
      echo $word is NOT in $file
   fi
   $

The test command for loops

The test command, which checks to see if certain conditions are true, is a useful command for conditional constructs. If the condition is true, the loop will continue. If the condition is false, the loop will end and the next command will be executed. Some of the useful options for the test command are:

test -r file true if the file exists and is readable
test -w file true if the file exists and has write permission
test -x file true if the file exists and is executable
test -s file true if the file exists and has at least one character
test var1 -eq var2 true if var1 equals var2
test var1 -ne var2 true if var1 does not equal var2
You may want to create a shell program to move all the executable files in the current directory to your bin directory. You can use the test -x command to select the executable files. Review the example of the for construct that occurs in the mv.file program, shown in the following screen:

   $ cat mv.file
   echo type in the directory path
   read path
   for file
   do
     mv $file $path/$file
   done
   $
Create a program called mv.ex that includes an if test -x statement in the do . . . done loop to move executable files only. Your program will be as follows:
   $ cat mv.ex
   echo type in the directory path
   read path
   for file
     do
       if test -x $file
          then
            mv $file $path/$file
       fi
     done
   $
The directory path is the path from the current directory to the bin directory. However, if you use the value for the shell variable HOME, you will not need to type in the path each time. $HOME gives the path to the login directory. $HOME/bin gives the path to your bin.

In the following example, mv.ex does not prompt you to type in the directory name, and therefore, does not read the path variable:

   $ cat mv.ex
   for file
     do
       if test -x $file
          then
            mv $file $HOME/bin/$file
       fi
     done
   $
Test the command, using all the files in the current directory, specified with the * special character as the command argument. The command lines shown in the following example execute the command from the current directory and then changes to bin and lists the files in that directory. All executable files should be there.
   $ mv.ex *
   $ cd; cd bin; ls
   list_of_executable_files
   $

case . . . esac

The case . . . esac construction has a multiple choice format that allows you to choose one of several patterns and then execute a list of commands for that pattern. The pattern statements must begin with the keyword in, and a ``)'' must be placed after the last character of each pattern. The command sequence for each pattern is ended with ``;;''. The case construction must be ended with esac (the letters of the word case reversed).

The general format for the case construction is shown in ``The case . . . esac conditional construct'':

   case word
   in
      pattern_1)
         command_line_1
            . . .
         last_command_line
      ;;
      pattern_2)
         command_line_1
            . . .
         last_command_line
      ;;
      pattern_3)
         command_line_1
            . . .
         last_command_line
   ;;
      *)
         command_1
            . . .
         last_command
      ;;
   esac

The case . . . esac conditional construct

The case construction tries to match the word following the word case with the pattern in the first pattern section. If a match exists, the program executes the command lines after the first pattern and up to the corresponding ``;;''.

If the first pattern is not matched, the program proceeds to the second pattern. Once a pattern is matched, the program does not try to match any more of the patterns, but goes to the command following esac.

The * used as a pattern matches any word, and so allows you to give a set of commands to be executed if no other pattern matches. To do this, it must be placed as the last possible pattern in the case construct, so that the other patterns are checked first. This helps you detect incorrect or unexpected input.

The patterns that can be specified in the pattern part of each section may use the special characters *, ``?'', and ``[]'' for filename expansion, as described earlier in this topic. This provides useful flexibility.

The set.term program contains a good example of the case . . . esac construction. This program sets the shell variable TERM according to the type of terminal you are using. It uses the following command line:

   TERM=terminal_name
In the following example, assume the terminal is a Teletype 4420, Teletype 5410, or Teletype 5420.

The set.term program first checks to see whether the value of term is 4420. If it is, the program makes T4 the value of TERM, and terminates. If it the value of term is not 4420, the program checks for other possible values: 5410 and 5420. It executes the commands under the first pattern it finds, and then goes to the first command after the esac command.

The pattern *, meaning everything else, is included at the end of the terminal patterns. It warns that you do not have a pattern for the terminal specified and it allows you to exit the case construct:

   $ cat set.term
   echo If you have a TTY 4420 type in 4420
   echo If you have a TTY 5410 type in 5410
   echo If you have a TTY 5420 type in 5420
   read term
   case $term
   	in
   		4420)
   			TERM=T4
   		;;
   		5410)
   			TERM=T5
   		;;
   		5420)
   			TERM=T7
   		;;
   		*)
   		echo not a correct terminal type
   		;;
   esac
   export TERM
   echo end of program
   $
Notice the use of the export command in the preceding screen. You use export to make a variable available within your environment and to other shell procedures. What would happen if you placed the * pattern first? The set.term program would never assign a value to TERM, since it would always match the first pattern *, which means everything.


Next topic: Unconditional control statements: break and continue
Previous topic: The shell's garbage can: /dev/null

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004