Loops


Sometimes you might want an operation to repeat until a certain condition becomes true (or until a certain condition is no longer true). This is where looping statements come into play. The Bourne shell supports three different looping constructs for these situations. These are the while loop, the until loop, and the for loop. You will look at each one separately.

The while Loop

The while loop takes a test condition as an argument, and repeats the statements inside the loop as long as the condition that is being tested is true. In other words, whatever is enclosed in the loop keeps being executed over and over until it causes a change in the program's variables such that the test condition becomes false. If the condition is already false the first time it is evaluated, the loop will never be executed. For example, the program in Listing 10.7 uses a while loop to count to 20 and display the numbers on the screen.

Listing 10.7. Using the while Loop

1.  #!/bin/sh 2.  # Count from 1 to 20 3.  i=1 4.  while [ $i -le 20 ] 5.  do 6.  echo $i 7.  i=`expr $i + 1` 8.  done

This program introduces a few new concepts:

  • Line 3 This line simply assigns the variable i the initial value of 1. i is a variable that is universally understood to be a loop-control counter; as with its usage in summation in mathematics, i typically stands for increment. This is one case where you can get away with not using a descriptive variable name.

  • Line 4 The while command contains the condition to test enclosed in brackets. The bracket is actually a shorthand notation for a command called test, which takes two operands and an operator used to compare them. You will use this command a lot in shell scripting.

    Unfortunately, the test command uses a somewhat strange syntax. -le in this example means "is less than or equal to." So this means the loop will repeat as long as the variable i is less than or equal to 20. For mathematical evaluations, Table 10.2 shows all the operators that this command supports.

    Table 10.2. Mathematical Operations for the test Command

    Option

    Action

    -eq

    Returns true if operand 1 is equal to operand 2

    -ne

    Returns true if operand 1 is not equal to operand 2

    -gt

    Returns true if operand 1 is greater than operand 2

    -ge

    Returns true if operand 1 is greater than or equal to operand 2

    -lt

    Returns true if operand 1 is less than operand 2

    -le

    Returns true if operand 1 is less than or equal to operand 2


  • Line 5 The do statement indicates that everything after this should be done for each iteration of the loop. All statements located between the do statement and the done statement are considered part of the loop.

  • Line 6 Prints the current value of the variable i.

  • Line 7 Uses command substitution with the expr command to increment the value of i by 1 and then assign the new value back into i.

  • Line 8 The done statement indicates the end of the loop. At this point, the program jumps back up to the while statement, and the test condition is evaluated again. If i is still less than or equal to 20, the statements inside the loop are repeated again. If i is greater than 20, the loop exits and control passes to the first statement after the done statement (in this case, line 9, which simply exits the program with a 0, or successful status).

Notice that the statements inside the loop are indented. This makes it easy to pick out the statements that are part of the loop when quickly scanning the program's source code. The shell ignores the indentation, so you could have written this program without using it. I recommend you always indent loops, though, using tabs or a specified number of spaces, to make them easier to find when quickly scanning program source code.

Tip

The space between the bracket ([) and the condition to be tested is mandatory, as is the space immediately before the final bracket (]). Failing to include either one will cause an error. For example,

[ $VarA -gt 5 ]


will work, but

[$VarA -gt 5]


will cause an error.


The until Loop

The until loop is the opposite of the while loop. It performs the operations inside the loop as long as the condition being tested is not true. When the condition being tested becomes true, the loop exits. If the condition is already true the first time it is evaluated, the loop will never be executed.

The while loop and the until loop are very similar. Usually, you can use either one in a program and achieve the same results simply by modifying the condition that is tested for. For example, the counting program that used the while loop can be rewritten to use an until loop by making only two changes in line 4:

4.  until [$i -gt 20 ]


This program performs the same function performed by the earlier program that uses the while loop. The only difference is that now the loop repeats until the value of i is greater than 20, whereas before it repeated while the value of i was less than or equal to 20. The result is exactly the same, however.

Logical AND/OR Statements in while and until Loops

Both the while loop and the until loop can also work with logical AND/OR statements. A logical AND statement, indicated with the symbol &&, will be carried out if and only if both conditions are true. A logical OR statement (||) will be carried out if either condition is true. The code example in Listing 10.8 shows a logical AND statement, which will execute the while loop only if both statements ("$VarA is equal to 1" and "$VarB is greater than 7") are true; the second statement is not true, so the loop will not execute.

Listing 10.8. Using a Logical AND Statement

1.  #!/bin/sh 2. 3.  # Demonstrate logical AND 4.  VarA=1 5.  VarB=5 6.  while [ $VarA -eq 1 ] && [ $VarB -gt 7 ] 7.  do 8.      echo "VarA is equal to 1 and VarB is greater than 7" 9.  done

In this example, the echo statement will not be executed. Because the while loop in this case requires both conditions to be true, the test fails and returns a 0 (false).

The code example in Listing 10.9 is identical to the one in Listing 10.8, except you have changed the while test to a logical OR statement. Now, only one of the conditions needs to be true. Therefore, because VarA will always be equal to 1 in this program, the while statement will continuously execute in an endless loop (until you press Ctrl+C).

Listing 10.9. Using a Logical OR Statement

1.  #!/bin/sh 2. 3.  # Demonstrate logical AND 4.  VarA=1 5.  VarB=5 6.  while [ $VarA -eq 1 ] || [ $VarB -gt 7 ] 7.  do 8.      echo "VarA is equal to 1 and VarB is greater than 7" 9.  done

The for Loop

The for loop is different from the while and until loops. Instead of evaluating a true/false test condition, the for loop simply performs the statements inside the body of the loop once for each argument it receives in a list. When creating a for loop, you supply it a variable. Each iteration of the for loop changes the value of the variable to the next argument in the list. The for loop continues until the argument list has been exhausted, at which point the loop exits and the program proceeds to the next command. The program in Listing 10.10 uses a for loop along with the bc command you learned about earlier to print the square root of all numbers from 10 through 20:

Listing 10.10. Using the for Loop

1.  #!/bin/sh 2.  # Print square roots of 10 - 20 3.  for num in `jot 10 10 20` 4.  do 5.     square_root=`echo "scale=5; sqrt($num)" | bc l` 6.     echo $square_root 7.  done

The output from this program is as follows:

3.16227 3.31662 3.46410 3.60555 3.74165 4.00000 4.12310 4.24264 4.35889 4.47213


Note these important lines in the preceding program:

  • Line 3 This line of the program contains the for loop. It introduces a new command called jot, which can do many useful operations with numbers, including printing a string of numbers and generating random numbers. In this case, you have used jot to print a string of 10 numbers, starting with number 10 and ending with the number 20 (10 10 20). The for loop assigns each one of these values to the variable num in sequence and then performs the statements in the body of the loop for each value.

  • Line 5 This line uses the bc command to compute the square root of the value stored in num. The scale=5 statement tells bc that the output should be scaled (truncated) to five significant digits after the decimal point. Notice also the semicolon after the scale statement. Semicolons can be used in place of a newline to separate multiple statements on the same line. The sqrt function of bc takes a number in parentheses and returns the square root of that number. Because the shell expands the variable to the value it contains, bc actually receives the number contained in the variable rather than the name of the variable itself. Finally, at the end of line 5, the output is piped to the bc command itself. The -l option tells bc to preload the math function library, which contains the sqrt function.

The shift Command

The shift command is similar to the for loop. You can use a while loop along with shift to run a loop once for each command-line argument you give when invoking a shell program.

As you'll recall from the previous discussion, command-line arguments are stored in numbered variables starting at $1 and going to $9. The shift command shifts the variables one position to the left each time it is run. This means that each time shift is encountered, the information currently stored in $1 "falls off" the end; the information currently stored in $2 is moved to $1, and so on up the list. Listing 10.11 shows an example.

Listing 10.11. Using the shift Command

1.  #!/bin/sh 2.  # This program demonstrates the use of shift. 3.  while [ $# -ne 0 ] 4.  do 5.      echo "The value of \$1 is now $1." 6.      shift 7.  done 8.  echo

And here's a sample run:

# ./shift1 a b c d e The value of $1 is now a. The value of $1 is now b. The value of $1 is now c. The value of $1 is now d. The value of $1 is now e.


Here are the notable lines in this program:

  • Line 3 This line starts a while loop. You will recall from the "Handling Command-Line Arguments" section that the magic variable $# contains the number of command-line arguments. This while loop continues as long as the value of $# is not equal to zero. When the value of $# is equal to zero, all the command-line arguments have been used up, and the loop ends.

  • Line 5 This line prints the current value of $1. Note that to actually print the literal string $1 on the screen, you have to escape the $ character with a backslash to prevent the shell from giving $ a special meaning.

  • Line 6 When the shift command in line 6 is run, the variables are shifted one position to the left. $1 "falls off" the end and is no longer available, $2 becomes $1, $3 becomes $2, and so on.

One of the most common applications of shift (and for loops) is in shell programs that accept a list of filenames as command-line arguments and then perform a group of operations on each file specified on the command line.

The true and false Statements

The sole purpose of the true and false statements in shell programming is to return a value of true (0) or false (1), respectively. You can use these statements to create infinite loops. As long as there is some condition that can break a program out of an infinite loop, it can be useful to write code that creates one. This is how programs are designed that run continuously and listen for input, such as web servers. The example in Listing 10.12 shows a program that will loop indefinitely.

Listing 10.12. Creating an Infinite Loop with true

1.  #!/bin/sh 2.  # The following program loops indefinitely. 3.  while true 4.  do 5.      echo "This line will print forever." 6.  done 7.  echo "This line will never print since the program will" 8.  echo "never get past the loop." 9.  exit 0      # The program will never exit cleanly since it will 10.             # never get to this point.

Obviously, this chapter cannot show you the output of this program because it would go on forever. Line 3 tests for a true condition. And because the argument it tests (TRue) will never return a value of false, the loop will repeat indefinitely. Lines 7, 8, 9, and 10 will never be executed because the program can never get past the loop. (To end this program, press Ctrl+C on your keyboard.)

Breaking the Loop

Sometimes, you might want to break out of a loop before the condition necessary to exit the loop has occurred, and then proceed with the rest of the script. There are two statements that can be used to break a loop without ending the program. The first is the break statement, and the second is the continue statement.

The break Statement

The break statement will terminate a loop immediately when it is encountered, regardless of whether the condition required to exit the loop has been met. Listing 10.13 shows a slight modification to the previous "endless loop" program.

Listing 10.13. Breaking Out of a Loop

1.  #!/bin/sh 2.  # The following program loops indefinitely. 3.  while true 4.  do 5.      echo "This line will print forever... But..." 6.      break 7.  done 8.  echo 9.  echo "The break statement in the loop causes the loop" 10. echo "to terminate immediately and go the first statement" 11. echo "after the loop."

Here's the output of this program:

This line will print forever... But... The break statement in the loop causes the loop to terminate immediately and go to the first statement after the loop.


In a more complex implementation, you could have a loop that waits for some kind of input to be entered from the user's console or from the network; the loop could test continuously for the existence of a file or the value of a variable, and if that condition becomes true, a break could end the loop. Usually it is considered more elegant to write loops whose exit conditions are constructed to react properly on the right kind of input and to avoid a break when possible. In sufficiently complex programs, however, a break can be just what you need to get out of a jam.

The continue Statement

The continue statement causes the loop to immediately jump back to the top and reevaluate the test condition. Any remaining statements in the loop are not executed. Listing 10.14 is another example that uses the "endless loop" program with a slight modification.

Listing 10.14. Restarting a Loop Before It Has Ended

1.  #!/bin/sh 2.  # The following program loops indefinitely. 3.  while true 4.  do 5.      echo "This line will print forever." 6.      continue 7.      echo "But this line will never print even though it is inside" 8.      echo "the loop because the preceding continue statement" 9.      echo "causes the loop to jump back to the top and reevaluate" 10.     echo "the test." 11. done 12. echo "This line will never print since the program will" 13. echo "never get past the loop." 14. exit 0      # The program will never exit cleanly since it will 15.             # never get to this point.

This program will indefinitely output "This line will print forever." The rest of the echo statements inside the loop will never be printed because the continue statement preceding them causes the loop to immediately jump back to the top and reevaluate the test condition.




FreeBSD 6 Unleashed
FreeBSD 6 Unleashed
ISBN: 0672328755
EAN: 2147483647
Year: 2006
Pages: 355
Authors: Brian Tiemann

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net