Main index

Introducing UNIX and Linux


More on shells

Overview
Simple arithmetic
      Arithmetic expansion
            Operators for arithmetic expansion
      The 'expr' command
Pattern matching
      Patterns
            Examples of patterns
      The case statement
Entering and leaving the shell
More about scripts with options
Symbolic links
Setting up terminals
Conventions used in UNIX file systems
Summary
Exercises

The 'expr' command

The command expr ('expression') performs a similar function to arithmetic expansion. In fact, it can be considered just a different syntax - just as [ expression ] can be replaced by test expression, so $(( expression )) can be replaced by expr expression. Non-POSIX shells will probably only support expr. There is, unfortunately, a catch. You can also use expr to perform more functions than just arithmetic - it is also capable of rudimentary operations on strings. If you give expr an argument that is not a 'sum', it will assume it is a string and print it:

expr hello
hello

Between $(( and )), the shell knows it is expecting an arithmetic expression. Following expr the shell does not know that what follows will be such an expression - it might be simply a string. For instance,

expr 1+2
1+2

In this example, 1+2 was not recognised by expr as '1 + 2'. In order for expr to work correctly with arithmetic, each 'token' - that is, number/operator - must be separated by whitespace:

expr 1 + 2
3

Since expr is simply a command like any other, any characters within the expression that are special to the shell (such as *) must be escaped, for instance:

expr 6 \* 7
42

If you had not escaped * in this example it would have been replaced by the names of all the files in the current directory. Another difference between arithmetic expansion and expr is that, for historical reasons, the equality operator for expr is =, not ==.

Worked example

Write a script to read in a number and decide whether or not that number is prime.
Solution: This calculation is one you would typically code in another programming language - it is not too complex to use the shell for, although efficiency considerations would discourage it. Using a variable I to iterate from 2 to half the possibly prime number N, keep checking whether or not I divides N exactly. If a divisor is found, set RESULT to 1. If we used bc for this, it would be extremely slow.

echo "Type in a number"
read N
RESULT=0
I=2
HALFN=$(( $N / 2 ))                # HALFN is N/2
while [ $I -le $HALFN ]            # Stop when I equals N/2
do
  if [ $(( $N % $I )) -eq 0 ]      # If I divides N exactly
  then RESULT=1                    # ... RESULT is 1
       break                       # ... and leave the loop
  fi
  I=$(( $I + 1 ))                  # Increment I
done
if [ $RESULT -eq 0 ]               # If no divisor found
then echo "$N is prime"
else echo "$N is composite"
fi

A better algorithm would have been to iterate to the square root of N rather than N/2, but arithmetic expansion doesn't allow for the square root function. Try this example using expr instead of arithmetic expansion.

We do not explore non-arithmetic capabilities of expr here.


Copyright © 2002 Mike Joy, Stephen Jarvis and Michael Luck