7

In shell script we can substitute expr $a*$b with $(($a+$b)).

But why not just with (($a+$b)), because in any resource it is written that (()) is for integer computation.

So we use $(()) when there are variables instead of integer values do we? And what should we use instead of $(()) when variables can receive float values?

14
  1. For arithmetic, expr is archaic. Don't use it.*

  2. $((...)) and ((...)) are very similar. Both do only integer calculations. The difference is that $((...)) returns the result of the calculation and ((...)) does not. Thus $((...)) is useful in echo statements:

    $ a=2; b=3; echo $((a*b))
    6
    

    ((...)) is useful when you want to assign a variable or set an exit code:

    $ a=3; b=3; ((a==b)) && echo yes
    yes
    
  3. If you want floating point calculations, use bc or awk:

    $ echo '4.7/3.14' | bc -l
    1.49681528662420382165
    
    $ awk 'BEGIN{print 4.7/3.14}'
    1.49682
    

*As an aside, expr remains useful for string handling when globs are not good enough and a POSIX method is needed to handle regular expressions.

  • 1
    If expr is archaic what should we use instead of expr text : '.*' – Stranger May 29 '16 at 8:44
  • If s is a shell variable, its length is ${#s} – John1024 May 29 '16 at 8:53
  • ${#} means a number of arguments and $(#s} means a number of characters of a variable does it? – Stranger May 29 '16 at 9:02
  • Yes. That's right. – John1024 May 29 '16 at 10:21
  • 4
    @Stranger Many uses of expr STRING : REGEX can be written as case STRING in PATTERN). expr is only useful when REGEX can't be expressed with shell wildcards. – Gilles 'SO- stop being evil' May 29 '16 at 23:10
2

expr is old, but it does have one limited use I can think of. Say you want to search a string. If you want to stay POSIX with grep, you need to use a pipe:

if echo november | grep nov 
then
  : do something
fi

expr can do this without a pipe:

if expr november : nov
then
  : do something
fi

the only catch is expr works with anchored strings, so if you want to match after the beginning you need to change the REGEXP:

if expr november : '.*ber'
then
  : do something
fi

Regarding (( )), this construct is not POSIX, so should be avoided.

Regarding $(( )), you do not have to include the dollar sign:

$ fo=1
$ go=2
$ echo $((fo + go))
3
  • 3
    Many uses of expr STRING : REGEX can be written as case STRING in PATTERN). expr is only useful when REGEX can't be expressed with shell wildcards. – Gilles 'SO- stop being evil' May 29 '16 at 23:08
0

It seems that the following programs do more or less the same and they don't really differ. But that is not true.

#!/bin/bash 
s=-1000
for (( i=0; i<1000000; i++ )), do
    s=$((s+1))
echo $s

This is the correct way to implement this. The expression s+1 is evaluated by the shell and can be assigned to a variable.

#!/bin/bash
s=-1000
for (( i=0; i<1000000; i++ )), do
    s=`expr $s+1`
echo $s

Here the expression will be calculated by the program expr, which isn't a shell builtin but an external Unix program. So instead of simply adding 1 and s a program must be started und its output must be read and written to the variable. Starting a programm needs a lot of resources and a lot of time. And this program is run 1000000 times. So the program will be much slower than the previous. Nevertheless the code works correctly.

#!/bin/bash -e
s=-1000
for (( i=0; i<1000000; i++ )), do
    ((s=s+1))
echo $s

If the -e flag isn't set, the program will work correctly, too. But if -e is set when s=-1 and ((s=s+1)) is calculated. The expression s=s+1 evaluates to 0 and the exit code of ((0)) is >0 which is interpreted as an error by the shell and the shell exits the program.

The reason to set the -e flag is that it is the simplest way of error processing: stop if an error ocurrs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.