Previous Section  < Day Day Up >  Next Section

10.6. Conditional Constructs and Flow Control

When making decisions, the if, if/else, if/else if, and switch commands are used. These commands control the flow of the program by allowing decision making based on whether an expression is true or false.

10.6.1 Testing Expressions

An expression consists of a set of operands separated by operators. Operators and precedence are listed in Tables 10.5 and 10.6, respectively. To test an expression, the expression is surrounded by parentheses. The C shell evaluates the expression, resulting in either a zero or nonzero numeric value. If the result is nonzero, the expression is true; if the result is zero, the expression is false.

Table 10.5. Comparison and Logical Operators

Operator

Meaning

Example

==

Equal to

$x == $y

!=

Not equal to

$x != $y

>

Greater than

$x > $y

>=

Greater than or equal to

$x >= $y

<

Less than

$x < $y

<=

Less than or equal to

$x <= $y

=~

String matches

$ans =~ [Yy]*

!~

String does not match

$ans !~ [Yy]*

!

Logical NOT

! $x

||

Logical OR

$x || $y

&&

Logical AND

$x && $y


When evaluating an expression with the logical AND (&&), the shell evaluates from left to right. If the first expression (before the &&) is false, the shell assigns false as the result of the entire expression, never checking the remaining expressions. Both expressions surrounding a logical && operator must be true for the entire expression to evaluate to true.


( 5 && 6 )   Expression is true

( 5 && 0 )   Expression is false

( 0 && 3 && 2 )   Expression is false


When evaluating an expression with the logical OR (||), if the first expression to the left of the || is true, the shell assigns true to the entire expression and never checks further. In a logical || expression, only one of the expressions must be true.


( 5 || 6 )   Expression is true

( 5 || 0 )   Expression is true

( 0 || 0 )   Expression is false

( 0 || 4 || 2 )   Expression is true


The logical NOT is a unary operator; that is, it evaluates one expression. If the expression to the right of the NOT operator is true, the expression becomes false. If it is false, the expression becomes true.


! 5   Expression is false

! 0   Expression is true


10.6.2 Precedence and Associativity

Like C, the C shell uses precedence and associativity rules when testing expressions. If you have an expression with a mix of different operators, such as the following, the shell reads the operators in a certain order:


@  x = 5 + 3 * 2

echo $x

11


Precedence refers to the order of importance of the operator. Associativity refers to whether the shell reads the expression from left to right or right to left when the precedence is equal.[2] Other than in arithmetic expressions (which you will not readily need in shell scripts anyway), the order of associativity is from left to right if the precedence is equal. You can change the order by using parentheses. (See Table 10.6.)

[2] Associativity in arithmetic expressions is right to left in cases of equal precedence.


@ x = ( 5 + 3 ) * 2

echo $x

16


Expressions can be numeric, relational, or logical. Numeric expressions use the following arithmetic operators:


+ – * /  ++ -- %


Relational expressions use the operators that yield either a true (nonzero) or false (zero) result:


>  <   >=   <=   ==   !=


Logical expressions use these operators that also yield true or false:


!   &&  ||


10.6.3 The if Statement

The simplest form of conditional is the if statement. After the if expression is tested, and if the expression evaluates to true, the commands after the then keyword are executed until the endif is reached. The endif keyword terminates the block. The if statement may be nested as long as every single if statement is terminated with a matching endif. The endif goes with the nearest enclosing if.

FORMAT


if ( expression ) then

    command

    command

endif


Example 10.11.

(In the Script: Checking for Arguments)

1   if ( $#argv != 1 ) then

2       echo "$0 requires an argument"

3       exit 1

4   endif


EXPLANATION

  1. This line reads: If the number of arguments ($#argv) passed in from the command line is not equal to one, then . . .

  2. If the first line is true, this line and line 3 are executed.

  3. The program exits with a value of 1, meaning it failed.

  4. Every if block is closed with an endif statement.

10.6.4 Testing and Unset or Null Variables

The $? special variable is used to test if a variable has been set. It will return true if the variable is set to some value, including null.

Example 10.12.

(From .cshrc/.tcshrc File)

if ( $?prompt ) then

    set history = 32

endif


EXPLANATION

The .cshrc file is executed every time you start a new csh program. $? is used to check to see if a variable has been set. In this example, the shell checks to see if the prompt has been set. If the prompt is set, you are running an interactive shell, not a script. The prompt is only set for interactive use. Because the history mechanism is only useful when running interactively, the shell will not set history if you are running a script.

Example 10.13.

(The Script)

    echo -n "What is your name? "

1   set name = $<

2   if ( "$name" != "" ) then

        grep "$name" datafile

    endif


EXPLANATION

  1. The user is asked for input. If the user just presses Enter, the variable name is set, but it is set to null.

  2. The variable is double quoted so that if the user enters more than one word in name, the expression will still be evaluated. If the quotes were removed and the user entered first and last name, the shell would exit the script with the error message if: Expression syntax. The empty double quotes represent a null string.

10.6.5 The if/else Statement

The if/else construct is a two-way branching control structure. If the expression following the if is true, the statements following it are executed; otherwise, the statements after the else are executed. The endif matches the innermost if statement and terminates the statement.

FORMAT


if ( expression ) then

    command

else

    command

endif


Example 10.14.

1   if ( $answer =~ [Yy]* ) then

2        mail bob < message

3   else

4        mail john < datafil   e

5   endif


EXPLANATION

  1. This line reads: If the value of $answer matches a Y or a y, followed by zero or more characters, then go to line 2; otherwise, go to line 3. (The * is a shell metacharacter.)

  2. The user bob is mailed the contents of the file message.

  3. The commands under the else are executed if line 1 is not true.

  4. The user john is mailed the contents of the file datafile.

  5. The endif block ends the if block.

10.6.6 Logical Expressions

The logical operators are &&, ||, and !. The AND operator, &&, evaluates the expression on the left-hand side of &&; if true, the expression on the right side of && is tested and must also be true. If one expression is false, the expression is false. The OR operator, ||, evaluates the expression on the left-hand side of ||; if true, the expression is true; if false, the expression on the right side of the || operator is tested. If it is true, the expression is true. If both expressions are false, the expression is false. The NOT operator, !, is a unary operator. It evaluates the expression on the right and if that expression is true, it becomes false, and if it is false, it becomes true. If one expression is false, the expression is false.

The –x option (called echoing) to the C/TC shell allows you to trace what is going on in your script as it executes. (See Chapter 15, "Debugging Shell Scripts," on page 967.)

Example 10.15.

(The Script: Using Logical Expressions and Checking Values)

    #!/bin/csh -f

    # Scriptname: logical

    set x = 1

    set y = 2

    set z = 3

1   if ( ( "$x" && "$y" ) ||  ! "$z" ) then

         # Note: grouping and parentheses

2        echo TRUE

    else

         echo FALSE

    endif



(The Output)

3   % csh -x logical

    set x = 1

    set y = 2

    set z = 3

    if  ( ( 1 &&  2 )  ||  !  3 )  then

    echo TRUE

    TRUE

    else

    %


EXPLANATION

  1. The logical expression is being evaluated. The first expression is enclosed in parentheses (not necessary because && is of higher precedence than ||). The parentheses do not require spaces when nested, but the negation operator (!) must have a space after it.

  2. If the expression evaluates true, this line is executed.

  3. The csh program is executed with the –x switch. This turns on echoing. Every line in your script is echoed back to you after variable substitution has been performed.

10.6.7 The if Statement and a Single Command

If an expression is followed by a single command, the then and endif keywords are not necessary.

FORMAT


if ( expression ) single command


Example 10.16.

if ($#argv == 0) exit 1


EXPLANATION

The expression is tested. If the number of command-line arguments, $#argv, is equal to 0, the program is exited with a status of 1.

10.6.8 The if/else if Statement

The if/else if construct offers a multiway decision-making mechanism. A number of expressions can be tested, and when one of the expressions evaluated is true, the block of statements that follow is executed. If none of the expressions is true, the else block is executed.

FORMAT


if ( expression ) then

    command

    command

else if ( expression ) then

    command

    command

else

    command

endif


Example 10.17.

(The Script: grade)

     #!/bin/csh -f

     # Scriptname: grade

     echo -n "What was your grade? "

     set grade = $<

1    if ( $grade >= 90 && $grade <= 100 ) then

          echo "You got an A\!"

2    else if ( $grade > 79 ) then

          echo "You got a B"

3    else if ( $grade > 69 ) then

          echo "You're average"

    else

4         echo "Better study"

5     endif


EXPLANATION

  1. If grade is greater than or equal to 90 and grade is less than or equal to 100, then You got an A! is printed. Both expressions surrounding the && must be true or program control will go to the else if on line 2.

  2. If line 1 is false, test the expression (line 2), and if it is true, You got a B is printed.

  3. If line 1 and 2 are both false, try this one. If this expression is true, then You're average is printed.

  4. If all of the above expressions test false, the statements in the else block are executed.

  5. The endif ends the entire if construct.

10.6.9 Exit Status and the Status Variable

Every UNIX/Linux command returns an exit status. If the command was successful, it returns an exit status of zero. If the command failed, it returns a nonzero exit status. You can test to see whether the command succeeded or failed by looking at the value of the C shell status variable. The status variable contains the exit status of the last command executed.

Example 10.18.

1   % grep ellie /etc/passwd

    ellie:pHAZk66gA:9496:41:Ellie:/home/jody/ellie:/bin/csh

2   % echo $status

    0                  # Zero shows that grep was a success



3   % grep joe /etc/passwd

4   % echo $status

    1                  # Nonzero shows that grep failed


EXPLANATION

  1. The grep program found ellie in the /etc/passwd file.

  2. The grep program, if it finds the pattern ellie, returns a zero status when it exits.

  3. The grep program did not find joe in the /etc/passwd file.

  4. The grep program returns a nonzero status if the pattern is not found.

10.6.10 Exiting from a Shell Script

In your shell script, the exit command will take you back to the shell prompt. The exit command takes an integer value to indicate the type of exit. A nonzero argument indicates failure; zero indicates success. The number must be between 0 and 255.

Example 10.19.

(The checkon Shell Script)

    #!/bin/csh -f

1   if ( $#argv != 1 ) then

2            echo "$0 requires an argument"




EXPLANATION

  1. If the number of arguments passed in from the command line ($#argv) is not equal to 1, then go to line 2.

  2. The echo prints the script name ($0) and the string requires an argument.

  3. The program exits back to the prompt with a value of 2. This value will be stored in the status variable of the parent shell.

  4. The end of the conditional if.

  5. At the command line, the program checkon is executed without an argument.

  6. The program exits with a value of 2, which is stored in the status variable.

10.6.11 Using an Alias to Create an Error Message

You may want to create a customized diagnostic message when exiting from a script due to some error condition. This can be accomplished with an alias, as shown in Example 10.20.

Example 10.20.

(The Script)

    #!/bin/tcsh -f

    # Scriptname: filecheck

    # Usage: filecheck filename

1   alias Usage 'echo "    Usage: $0 filename\!*" ; exit 1'

2   alias Error 'echo "    Error: \!* "; exit 2'

3   set file=$1

4   if ( $#argv == 0 ) then

       Usage

    endif

5   if ( ! -e $file ) then

         Error "$file does not exist"

    endif



(The Command Line)

% filecheck

Usage: filecheck filename

% echo status

1



% filecheck xyzfile

Error: xyzfile does not exist

% echo $status

2


10.6.12 Using the Status Variable in a Script

The status variable can be used in a script to test the status of a command. The status variable is assigned the value of the last command that was executed.

Example 10.21.

(The Script)

    #!/bin/csh -f

1   ypmatch  $1  passwd >& /dev/null

2   if ( $status == 0 ) then

3         echo Found $1 in the NIS database

    endif


EXPLANATION

  1. The ypmatch program checks the NIS database to see if the name of the user, passed in as the first argument, is in the database.

  2. If the status returned from the last command is 0, the then block is executed.

  3. This line is executed if the if test expression evaluated to be true.

10.6.13 Evaluating Commands Within Conditionals

The C shell evaluates expressions in conditionals. To evaluate commands in conditionals, curly braces must enclose the command. If the command is successful, that is, returns an exit status of zero, the curly braces tell the shell to evaluate the expression as true (1).[3] If the command fails, the exit status is nonzero, and the expression is evaluated as false (0).

[3] The command's exit status is inverted by the shell so that the expression yields a true or false result.

It is important, when using a command in a conditional, to know the exit status of that command. For example, the grep program returns an exit status of 0 when it finds the pattern it is searching for, 1 when it cannot find the pattern, and 2 when it cannot find the file. When awk or sed are searching for patterns, those programs return 0 whether or not they are successful in the pattern search. The criterion for success with awk and sed is based on whether the syntax is correct; that is, if you typed the command correctly, the exit status of awk and sed is 0.

If the exclamation mark is placed before the expression, it NOTs the entire expression so that if true, it is now false, and vice versa. Make sure a space follows the exclamation mark, or the C shell will invoke the history mechanism.

FORMAT


if  { ( command ) }  then

     command

     command

endif


Example 10.22.

    #!/bin/csh -f

1   if  { ( who | grep $1 >& /dev/null ) } then

2        echo $1 is logged on and running:

3        ps -ef | grep "^ *$1"       # ps –aux for BSD

4   endif


EXPLANATION

  1. The who command is piped to the grep command. All of the output is sent to /dev/null, the UNIX/Linux "bit bucket." The output of the who command is sent to grep; grep searches for the name of the user stored in the $1 variable (the first command-line argument). If grep is successful and finds the user, an exit status of 0 is returned. The shell will then invert the exit status of the grep command to yield 1, or true. If the shell evaluates the expression to be true, it executes the commands between the then and endif.

  2. If the C/TC shell evaluates the expression in line 1 to be true, lines 2 and 3 are executed.

  3. All the processes running and owned by $1 are displayed.

  4. The endif ends the if statements.

FORMAT


if ! { (command) } then


Example 10.23.

1   if  !  { ( ypmatch $user passwd >& /dev/null ) } then

2        echo $user is not a user here.

         exit 1

3   endif


EXPLANATION

  1. The ypmatch command is used to search the NIS passwd file, if you are using a network. If the command succeeds in finding the user ($user) in the passwd file, the expression evaluates to be true. The exclamation point (!) preceding the expression NOTs or complements the expression; that is, makes it false if it is true, and vice versa.

  2. If the expression is not true, the user is not found and this line is executed.

  3. The endif ends this if block.

10.6.14 The goto

A goto allows you to jump to some label in the program and start execution at that point. Although gotos are frowned on by many programmers, they are sometimes useful for breaking out of nested loops.

Example 10.24.

(The Script)

     #!/bin/csh -f

1    startover:

2    echo "What was your grade? "

     set grade = $<

3    if ( "$grade" < 0 || "$grade" > 100 ) then

4         echo "Illegal grade"

5         goto startover

     endif

     if ( $grade >= 89 ) then

          echo "A for the genius\!"

     else if ( $grade >= 79 ) then

         .. < Program continues >


EXPLANATION

  1. The label is a user-defined word with a colon appended. The label is called startover. During execution of the program, the label is ignored by the shell, unless the shell is explicitly directed to go to the label.

  2. The user is asked for input.

  3. If the expression is true (the user entered a grade less than 0 or greater than 100), the string Illegal grade is printed, and the goto starts execution at the named label, startover. The program continues to execute from that point.

  4. The if expression tested false, so this line is printed.

  5. The goto sends control to line 1 and execution starts after the label, startover.

10.6.15 File Testing with the C Shell

Both the C and TC shells have a built-in set of options for testing attributes of files, such as whether it is a directory, a plain file (not a directory), a readable file, and so forth. The TC shell adds a few more features in this area, which will be discussed in "File Testing with the TC Shell" on page 551. For other types of file tests, the UNIX/Linux test command is used. The built-in options for file inquiry are listed in Table 10.7.

Example 10.25.

    #!/bin/csh -f

1   if ( –e file ) then

         echo file exists

    endif

2   if ( –d file ) then

          echo file is a directory

    endif





3   if ( ! –z file ) then

          echo file is not of zero length

    endif

4   if ( -r file && -w file ) then

          echo file is readable and writable

    endif


Table 10.7. File Testing with the C Shell

Test Flag

(What It Tests) True If

–d

File is a directory

–e

File exists

–f

File is a plain file

–o

Current user owns the file

–r

Current user can read the file

–w

Current user can write to the file

–x

Current user can execute the file

–z

File is zero length


EXPLANATION

  1. The statement reads: if the file exists, then . . .

  2. The statement reads: if the file is a directory, then . . .

  3. The statement reads: if the file is not of zero length, then . . .

  4. The statement reads: if the file is readable and writable, then . . . . The file-testing flags cannot be stacked, as in –rwx file. A single option precedes the filename (e.g., –r file && –w file && –x file).

10.6.16 The test Command and File Testing

The UNIX/Linux test command includes options that were built into the C shell, as well as a number of options that were not. See Table 10.8 for a list of test options. You may need these additional options when testing less common attributes of files such as block and special character files, or setuid files. The test command evaluates an expression and returns an exit status of either 0 for success or 1 for failure. When using the test command in an if conditional statement, curly braces must surround the command so that the shell can evaluate the exit status properly.[4]

[4] A common error is to name your script test. If your search path contains the UNIX test command first, it will execute it instead of your script. The test command either displays an error or nothing at all if the syntax is correct.

Example 10.26.

1   if { test –b file } echo file is a block special device file



2   if { test –u file }  echo file has the set–user–id bit set


Table 10.8. File Testing with the test Command

Option

Meaning—Tests True If

–b

File is a block special device file

–c

File is a character special device file

–d

File exists and is a directory file

–f

File exists and is a plain file

–g

File has the set-group-ID bit set

–k

File has the sticky bit set

–p

File is a named pipe

–r

Current user can read the file

–s

File exists and is not empty

–t n

n is file descriptor for terminal

–u

File has the set-user-ID bit set

–w

Current user can write to the file

–x

Current user can execute the file


EXPLANATION

  1. The statement reads: if the file is a block special device file (found in /dev), then . . .

  2. The statement reads: if the file is a setuid program (set user ID), then . . .

10.6.17 Nesting Conditionals

Conditional statements can be nested. Every if must have a corresponding endif (else if does not have an endif). It is a good idea to indent nested statements and line up the ifs and endifs so that you can read and test the program more effectively.

Example 10.27.

(The Script)

     #!/bin/csh -f

     # Scriptname: filecheck



     # Usage: filecheck filename



     set file=$1











(The Command Line)

$ filecheck testing

You have read and execute permission of file testing.


EXPLANATION

  1. If file (after variable substitution) is a file that does not exist (note the NOT operator, !), the commands under the then keyword are executed. An exit value of 1 means that the program failed.

  2. If the file is a directory, print testing is a directory.

  3. If the file is not a directory, else if the file is a plain file, then . . . the next statement is executed, another if.

  4. This if is nested in the previous if. If file is readable, writable, and executable, then . . . . This if has its own endif and is lined up to indicate where it belongs.

  5. The endif terminates the innermost if construct.

  6. The endif terminates the outermost if construct.

10.6.18 File Testing with the TC Shell

The TC shell, like the C shell, has a built-in set of options for testing attributes of files, such as whether the file is a directory, a plain file (not a directory), a readable file, and so forth. But the TC shell provides additional techniques for file testing as listed below.

The operators listed in Table 10.9 return 1 for true and 0 for false after testing an attribute of a file or directory in terms of the real user. The built-in options for file inquiry are listed in Table 10.10 on page 554. The TC shell allows these operators to be bound together (the C shell does not). The form –rwx is the same as –r && –w && –x.

Example 10.28.

(The Script)

     #!/bin/tcsh -f

     # Scriptname: filetest1

1    if ( –e file ) then

        echo file exists

     endif

2    if ( –d file ) then

        echo file is a directory

     endif

3    if ( ! –z file ) then

        echo file is not of zero length

     endif



4    if ( -r file && -w file && -x file) then

        echo  file is readable and writable and executable.

     endif

5    if ( -rwx file ) then

        echo file is readable and writable and executable.

     endif


Table 10.9. File Testing with the TC Shell

Test Flag

(What It Tests) True If

-b

File is a block special file

-c

File is a character special file

-d

File is a directory

-e

File exists

-f

File is a plain file

-g

Set-group-ID bit is set

-k

Sticky bit is set

-l

File is a symbolic link

-L

Applies subsequent operators in a multiple-operator list to a symbolic link rather than to the file to which it is linked

-o

Current user owns the file

-p

File is named pipe (fifo)

-r

Current user can read the file

-R

Has been migrated (convex only)

-s

File is nonzero size

-S

File is a socket special file

-t file

file (must be a digit) is an open file descriptor for a terminal device

-w

Current user can write to the file

-x

Current user can execute the file

-z

File is zero length


Table 10.10. Additional tcsh File Tests

Operator

What It Does

-A

Last file access time, as the number of seconds since the epoch (Jan. 1, 1970)

-A:

Like A, but in timestamp format, e.g., Fri. Aug. 27 16:36:10 2004

-M

Last file modification time

-M:

Like M, but in timestamp format

-C

Last inode modification time

-C:

Like C, but in timestamp format

-F

Composite file identifier, in the form device:inode

-G

Numeric group ID

-G:

Group name or numeric group ID if the group name is unknown

-L

The name of the file pointed to by a symbolic link

-N

Number of (hard) links

-P

Permissions, in octal, without a leading zero

-P:

Like P, with leading a zero

-Pmode

Equivalent to -P file & mode; e.g., -P22 file returns 22 if file is writable by group and other, 20 if by group only, and 0 if by neither

-Mode:

Like PMode:, with leading zero

-U

Numeric user ID

-U:

Username, or the numeric user ID if the username is unknown

-Z

Size, in bytes


EXPLANATION

  1. The statement reads: if the file exists, then . . .

  2. The statement reads: if the file is a directory, then . . .

  3. The statement reads: if the file is not of zero length, then . . .

  4. The statement reads: if the file is readable and writable, then . . . A single option precedes the filename (e.g., –r file && –w file && –x file).

  5. The file-testing flags can be stacked (only with tcsh), as in –rwx file.

Example 10.29.

(The Script)

     #!/bin/tcsh -f

     # Scriptname: filetest2

1    foreach file (`ls`)

2       if ( -rwf $file ) then

3          echo "${file}: readable/writable/plain file"

        endif

     end



(Output)

3  complete: readable/writable/plain file

   dirstack: readable/writable/plain file

   file.sc: readable/writable/plain file

   filetest: readable/writable/plain file

   glob: readable/writable/plain file

   modifiers: readable/writable/plain file

   env: readable/writable/plain file


EXPLANATION

  1. The foreach loop iterates through the list of files produced by the UNIX/Linux ls program, one file at a file, assigning each filename to the variable file.

  2. If the file is readable, writable, and a plain file (–rwf), line number 3 is executed. The stacking of these file-testing options is legal in tcsh, but not in csh.

  3. This line is executed if the filename being tested is readable, writable, and executable.

10.6.19 The filetest Built-In (tcsh)

The tcsh built-in filetest command applies one of the file inquiry operators to a file or list of files and returns a space-separated list of numbers; 1 for true and 0 for false.

Example 10.30.

1   > filetest -rwf dirstack file.sc xxx

    1 1 0

2   > filetest -b hdd

    1

3   > filetest -lrx /dev/fd

    1


EXPLANATION

  1. Each of the files, dirstack, file.sc, and xxx, are tested to see if they are readable, writable, plain files. For the first two files the test returns true (1 1), and for the last the test returns false (0).

  2. The filetest command returns 1 if the file, hdd, is a block special device file. It is. Otherwise, 0 is returned.

  3. The filetest command returns 1 if the file, fd, is a symbolic link and is readable and executable. It is. Otherwise, 0 is returned.

10.6.20 Additional TC Shell File-Testing Operators

There is an additional set of file-testing operators (tcsh only), shown in Table 10.10, that return information about files. Because the returned values are not true/false values, a –1 indicates failure (except F , which returns a :).

Example 10.31.

1   > date

    Wed Apr 22 13:36:11 PST 2004

2   > filetest -A myfile

    934407771

3   > filetest -A: myfile

    Wed Apr 22 14:42:51 2004

4   > filetest -U myfile

    501

5   > filetest -P: myfile

    0600

    > filetest -P myfile

    600


EXPLANATION

  1. Today's date is printed.

  2. With the –A option, the filetest built-in prints the date (in epoch form) when myfile was last accessed.

  3. With the –A: option, the filetest built-in prints the date in timestamp format.

  4. With the –U option, the filetest built-in prints the numeric user ID for the owner of myfile.

  5. With the –P: option, the filetest built-in prints the octal permission mode with a leading 0. Without the colon, the leading 0 is removed.

Example 10.32.

(The Script)

     #!/bin/tcsh -f

     # Scriptname: filecheck

     # Usage: filecheck filename

1    alias Usage 'echo "    Usage: $0 filename\!*" ; exit 1'

2    alias Error 'echo "    Error: \!* "; exit 2'



    You have read and execute permission on file testing1.


EXPLANATION

  1. This alias, Usage, can be used to produce an error message and exit the program.

  2. This is an alias called Error that will produce an error message followed by any arguments passed when called.

  3. The variable file is set to the first argument passed in from the command line, $1 (i.e., testing1).

  4. If the number of arguments passed is 0, that is, no arguments were provided, the alias Usage will print its message to the screen.

  5. If file (after variable substitution) is a file that does not exist (note the NOT operator, !), the alias, Error, under the then keyword displays its message.

  6. If the file is a directory, print "testing1 is a directory."

  7. If the file is not a directory, else if the file is a plain file, then . . . the next statement is executed, another if.

  8. This if is nested in the previous if. If file is readable and executable, then . . . This if has its own endif and is lined up to indicate where it belongs.

  9. The endif terminates the innermost if construct.

  10. The endif terminates the outermost if construct.

10.6.21 The switch Command

The switch command is an alternative to using the if–then–else if construct. Sometimes the switch command makes a program clearer to read when handling multiple options. The value in the switch expression is matched against the expressions, called labels, following the case keyword. The case labels will accept constant expressions and wildcards. The label is terminated with a colon. The default label is optional, but its action is taken if none of the other cases match the switch expression. The breaksw is used to transfer execution to the endsw. If a breaksw is omitted and a label is matched, any statements below the matched label are executed until either a breaksw or endsw is reached.

FORMAT


switch (variable)

case constant:

     commands

     breaksw

case constant:

     commands

     breaksw

endsw


Example 10.33.

(The Script)

     #!/bin/csh -f

     # Scriptname: colors

1    echo -n "Which color do you like? "

2    set color = $<

3    switch ("$color")

4    case bl*:

          echo I feel $color

          echo The sky is $color

5         breaksw

6    case red:          # Is is red or is it yellow?

7    case yellow:

8         echo The sun is sometimes $color.

9         breaksw

10   default:

11        echo $color is not one of the categories.

12        breaksw

13   endsw



(The Command Line)

% colors



(The Output)

1    Which color do you like? red

8    The sun is sometimes red.

1    Which color do you like? Doesn't matter

11   Doesn't matter is not one of the categories.


EXPLANATION

  1. The user is asked for input.

  2. The input is assigned to the color variable.

  3. The switch statement evaluates the variable. The switch statement evaluates a single word or string of words if the string of words is held together with double quotes.

  4. The case label is bl*, meaning that the switch expression will be matched against any set of characters starting with b, followed by an l. If the user entered blue, black, blah, blast, and so forth, the commands under this case label would be executed.

  5. The breaksw transfers program control to the endsw statement.

  6. If the switch statement matches this label, red, the program starts executing statements until the breaksw on line 9 is reached. Line 8 will be executed. The sun is sometimes red. is displayed.

  7. If line 6 is not matched (i.e., the color is not red), case yellow is tested.

  8. If either label, red or yellow , is matched, this line is executed.

  9. The breaksw transfers program control to the endsw statement.

  10. The default label is reached if none of the case labels matches the switch expression. This is like the if/else if/else construct.

  11. This line is printed if the user enters something not matched in any of the above cases.

  12. This breaksw is optional because the switch will end here. It is recommended to leave the breaksw here so that if more cases are added later, they will not be overlooked.

  13. The endsw terminates the switch statement.

Nesting Switches

Switches can be nested; that is, a switch statement and its cases can be contained within another switch statement as one of its cases. There must be an endsw to terminate each switch statement. A default case is not required.

Example 10.34.

(The Script)

     #!/bin/csh -f

     # Scriptname: systype

     # Program to determine the type of system you are on.

     echo "Your system type is: "

1    set release = (`uname -r`)

2    switch (`uname -s`)

3    case SunOS:

4         switch ("$release")

5         case 4.*:

                   echo "SunOS $release"

                   breaksw

6         case [5-9].*:

                   echo "Solaris $release"

                   breaksw

7         endsw

          breaksw

     case HP*:

          echo HP-UX

          breaksw

     case Linux:

          echo Linux

          breaksw

8    endsw



(The Output)

Your system type:

SunOS 4.1.2


EXPLANATION

  1. The variable release is assigned the output of uname –r, the release number for the version of the operating system.

  2. The switch command evaluates the output of uname –s, the name of the operating system.

  3. If the system type is SunOS, the case command on line 3 is executed.

  4. The value of the variable release is evaluated in each of the cases for a match.

  5. The case for all release versions 4 are tested.

  6. The case for all release versions 5–9 are tested.

  7. The inner switch statement is terminated.

  8. The outer switch statement is terminated.

10.6.22 The here document and Menus

The here document (discussed in "The here document" on page 433) is used in shell scripts to produce a menu. It is often used in conjunction with the switch statement. Once the user has seen the menu, he or she selects an item, and then the choice is matched in the switch statement to the case that corresponds to the choice. The here document reduces the number of echo statements that would otherwise be needed and makes the program easier to read.

Example 10.35.

(The Script)

     #! /bin/tcsh

1    echo "Select from the following menu:"

2    cat << EOF

        1) Red

        2) Green

        3) Blue

        4) Exit

3    EOF

4    set choice = $<

5    switch ("$choice")

6    case 1:

            echo Red is stop.

7           breaksw

     case 2:

            echo Green is go\!

            breaksw

     case 3:

            echo Blue is a feeling...

            breaksw

     case 4:

            exit

            breaksw

     default:

            echo Not a choice\!\!

     endsw

8    echo Good-bye



(The Output)

Select from the following menu:

     1) Red

     2) Green

     3) Blue

     4) Exit

2

Green is go!

Good-bye


EXPLANATION

  1. The user is asked to select from the menu produced by the here document on line 2.

  2. The here document is used to display a list of color choices.

  3. EOF marks the end of the here document.

  4. The user input is assigned to the variable choice.

  5. The switch statement evaluates the variable choice and proceeds to match the user's choice to one of the cases.

  6. If the user selected 1, Red is stop is displayed and the breaksw command on line 7 causes the program to exit the switch and go to line 8. If the user didn't select 1, then the program starts at case 2, and so on.

    Previous Section  < Day Day Up >  Next Section