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.
|