Arithmetic in Shell Programs


Although the original Bourne shell has no built-in arithmetic handlers, arithmetic can still be done using command substitution along with the expr command. Here's an example:

var3=`expr var1 + var2`


This adds the values contained in var1 and var2 together and then stores the result in var3. Note that the arguments and the operator must be separated by whitespace. expr var1+var2 will not have the intended result.

The expr command can do only very simple mathit can handle only integer arithmetic. Entering floating-point numbers will cause an error. Changing the order of operations with parentheses is not supported. Division that does not return an integer value will have the decimal portion dropped. For example, 5 / 2 is 2 as far as expr is concerned. If you want to retrieve the remainder of a division, you can use the modulus operator (%). For example, expr 5 % 2 will return 1 (5 / 2 = 4 remainder 1).

Characters that have special meaning to the shell must be escaped. For example, expr 2 * 2 will not work because the shell interprets the * as a wildcard operator. For the operation to work, the multiplication operator (*) must be escaped like this: expr 2 \* 2. This protects it from the shell's interpreting it as having a special meaning.

expr can also evaluate true/false expressions. If the expression is true, expr returns a 1. If the expression is false, expr returns 0. Here's an example:

expr 2 + 2 = 4 + 1


This command returns 0 (the equation is false).

This next example returns 1 (the equation is true):

expr 2 + 2 = 3 + 1


!= will reverse the sense of the equationit means "is not equal to." So, for example, the equation expr 5 != 3 will return 1 (true).

expr can, of course, also evaluate less than/greater than comparisons. Once again, because the < and > characters have special meaning to the shell, they must be escaped when used with expr to make sure they retain their mathematical meanings. Comparisons are true/false evaluations just like the "equal to" operator. If the expression is true, expr returns 1. If the expression is false, expr returns 0. For example, expr 5 \> 4 returns 1 (the expression is true). Greater than or equal to (\>=) and less than or equal to (\<=) evaluations are also supported.

expr is not limited to comparing numbersit can also compare strings. For example, expr "The quick brown fox jumps over the lazy dog" = "The quick brown fox jumps over the lazy dg" will evaluate to 0 (the expression is false unless the strings are exactly equal).

Although expr is great for simple shell scripting, as mentioned previously, its capabilities are rather limited. If you need to do floating-point math, work with complex expressions that change the order of operations, and so on, you can use a command called bc, which is a programming language in itself designed for working more flexibly with math than can be done in the basic shell language. It's possible to embed expressions into your shell program and feed them to bc. The program in Listing 10.6 uses bc to compute both the circumference and the area of a circle. Note that the argument to bc is l, the lowercase letter L. This option defines the standard math library for bc.

Listing 10.6. Using bc to Compute the Circumference and Area of a Circle

1.  #!/bin/sh 2. 3.  # The Following program computes both the circumference and the area 4.  # of a circle. 5. 6.  pi="3.14159265"         # Assign the value of pi to a variable. 7. 8.  # Tell the user what the program does and ask them for the radius of 9.  # the circle. 10. 11. echo 12. echo "This program computes both the circumference and the area of" 13. echo "a circle." 14. echo 15. echo -n "Please enter the radius of the circle: " 16. read radius 17. 18. # Now we will use bc to compute the answers and store them in variables. 19. 20. circumference=`echo "$radius*$pi" | bc l` 21. area=`echo "$radius^2*$pi" | bc l` 22. 23. # Last, we display the answers to the user and exit. 24. 25. printf "\n\nThe circumference is:\t$circumference\n" 26. printf "The area is:\t\t$area\n\n"

Most of the concepts used in this program have already been explained, in the sections "Variables" and "Interacting with the User." Therefore, rather than go through the program line by line, we'll just cover the concepts that are new and/or important to the operation of the program:

  • Line 6 This line assigns a reasonably accurate value of Π to a variable called pi. I point this out because it shows good programming practice. You could just as easily have typed the number 3.14159265 each time you needed to use Π in the program.

    But assigning this irrational number to a variable serves two primary purposes. First, it simply makes the program more readable, minimizing the number of long numeric strings that would have to appear. Second, it makes the program much easier to maintain. If you later decided that you needed more precision for the value of Π, you would only have to change one number where you assign the value to the variable pi. If you had used the actual number each time in the program when you needed it, you would have to find and change each occurrence of Π when you decided you need more precision. This practice also aids in debugging; keeping all your variable declarations in one place and referring repeatedly back to it means that a typo will cause a problem much earlier and allow you to fix it much more directly.

  • Line 16 As shown earlier, the read command gathers data from STDIN. In this case, you read the value typed by the user and store it in the variable radius.

  • Line 20 Line 20 uses command substitution and a pipe to compute the circumference of the circle and store the value in the variable circumference. Because bc does not accept expressions directly on the command line, you need to use the echo command to echo the expression you want computed and then pipe the output of echo to bc.

  • Line 21 This line is similar to line 20. The caret (^) in the expression is the bc exponent operator. In this case, it raises the value stored in radius by the power of 2 (you may recall from geometry that the area of a circle is obtained by squaring the radius and then multiplying by pi). You do not need to use parentheses to change the order of operation because, as you may recall from algebra, exponents have higher precedence than multiplication. Therefore, you can be assured that the exponent will be evaluated before the multiplication is done.

  • Lines 25 and 26 These lines display the results to the user. I used printf here because it gives me a nicer layout than echo. The use of the \t expression creates tabs and causes the numbers to line up in a nice column.

This is only a very simple use of bc. bc is quite powerful and can do much more than the examples you've seen here. See the man page for bc if you are interested in learning more about its capabilities, both inside shell scripts and in standalone programs.




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