|
|
Conditional constructs cause branches in the path of execution based on the outcome of a comparison.
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/nullNow execute your search program. It should respond only with the message specified after the echo command.
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, 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 |
$ 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 $
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_nameIn 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.