196

I can read the numbers and operation in with:

echo "First number please"
read num1
echo "Second number please"
read num2
echo "Operation?"
read op

but then all my attempts to add the numbers fail:

case "$op" in
  "+")
    echo num1+num2;;
  "-")
    echo `num1-num2`;;
esac

Run:

First number please
1
Second mumber please
2
Operation?
+

Output:

num1+num2

...or...

echo $num1+$num2;;

# results in: 1+2    

...or...

echo `$num1`+`$num2`;;

# results in: ...line 9: 1: command not found

Seems like I'm getting strings still perhaps when I try add add ("2+2" instead of "4").

dhag
  • 15,736
  • 4
  • 55
  • 65
  • 5
    I edited your title because this is a good general question, and if you narrowed the context down you would have realized this has nothing to do with case or anything except one line: echo $num+$num, since that will reproduce the problem exactly. The idea with minimizing context in programming questions is explained here: http://sscce.org/ – goldilocks Sep 30 '13 at 16:47
  • 3
    +1 Hi goldilocks, yes that became clear to me afterwards, but yes I totally agree with your line of reasoning and yes, the more specific and 'singular' a question is the better. I welcome your edit(s) :) Thank You :) – Michael Durrant Sep 30 '13 at 17:04

6 Answers6

283

Arithmetic in POSIX shells is done with $ and double parentheses (( )):

echo "$(($num1+$num2))"

You can assign from that; also note the $ operators on the variable names inside (()) are optional):

num1="$((num1+num2))"

There is also expr:

expr $num1 + $num2

In scripting $(()) is preferable since it avoids a fork/execute for the expr command.

goldilocks
  • 87,661
  • 30
  • 204
  • 262
  • 2
    Or even directly echo $(($num1$op$num2)) without involving case. – manatwork Sep 30 '13 at 16:44
  • There's no case involved here. – goldilocks Sep 30 '13 at 16:49
  • 2
    No, but you used literal +, so will need the case outside to handle the subtraction separately. – manatwork Sep 30 '13 at 16:51
  • 1
    @manatwork : You mean eliminate the case from the OP's code with echo $(($num1$op$num2)) -- that will work, but using the case is more robust since you can handle errors with a default *. – goldilocks Sep 30 '13 at 17:04
  • +1 to both of you. I was using case (might not have shown it at the start) but as you both realized the problem wasn't about the case. – Michael Durrant Sep 30 '13 at 17:05
  • The $((..)) arithmetic evaluation is executed by bash, whereas expr is executed as a separate process. Hence, the latter is slower than $((..)). Use expr only on systems where arithmetic evaluation is not supported (sh!=bash). – Serge Stroobandt May 06 '14 at 13:32
  • @SergeStroobandt: IIRC, (()) arithmetic contexts are part of POSIX sh. You can do ((newvar = num1 + num2)) as its own command, or C-style for loops. Some non-POSIX shells don't support it, though. Also, echo $(expr) makes no sense. Why capture expr output just to put it on echo's commandline? Just so it can be word-split / glob-expanded? – Peter Cordes Sep 09 '15 at 10:41
  • Only expressions $((...)) are defined by POSIX; stand-alone statements ((...)) are a bash extension. – chepner Nov 01 '15 at 18:05
  • $[...] is an old, pre-POSIX notation for arithmetic expressions. Recognize it, but don't use it in new code. (It's not even mentioned in the man page anymore.) – chepner Nov 01 '15 at 18:06
  • @chepner Thx. Edited. – goldilocks Nov 01 '15 at 18:26
  • 3
    Note that you can write var instead of $var (the $ prefix is not needed) inside the expression: echo $(( num1 + num2 )) – Philipp Jun 01 '21 at 15:26
  • I agree with @Philipp and want to add that num1 + num2 without the $ sign reinforces the fact you are in a math statement. Plus shellcheck will probably nag you to death if you use $ inside the command. – WinEunuuchs2Unix Oct 14 '21 at 01:54
  • Note that this doesn't work with decimal numbers – Flimm Jan 12 '23 at 14:15
19

The existing answer is pure bash, so it will be faster than this, but it can only handle integers. If you need to handle floats, you have to use the external program bc.

$ echo 'scale=4;3.1415+9.99' | bc
13.1315

The scale=4 tells bc to use four decimal places. See man bc for more information.

evilsoup
  • 6,807
  • 3
  • 34
  • 40
  • Note that while bash doesn't support floating point arithmetics with $((...)), many shells (ksh93, zsh, yash at least) do. The advantage of bc is that it supports arbitrary precision while shell arithmetics is limited to the processor's double type. Note that you don't need to set scale here. For additions, the scale parameter is not used. The scale of 3.1415+9.99 will be derived from that of the operands (here 4). – Stéphane Chazelas Dec 20 '16 at 12:06
  • How to do the math if one value is 450 and the other is decimal stored on a variable $mynumber? For example, 450-$mynumber. – Sigur Mar 17 '17 at 22:34
  • @sigur echo "450-$mynumber" | bc should do it. If you want a variable to expand you have to use double quotes rather than single quotes. – evilsoup Mar 17 '17 at 23:22
  • @evilsoup, now it works like a charm. Thanks. – Sigur Mar 17 '17 at 23:30
  • computedval=$(echo 'scale=10;var1-var2' | bc) doesn't work, nor does computedval=$(echo 'scale=10;$var1-$var2' | bc) – StatsSorceress May 03 '19 at 01:50
  • Found one that worked: computedval=$(bc <<< "scale=10; $val1-$val2") – StatsSorceress May 03 '19 at 01:55
10

You can also use $[ ... ] structure. In this case, we use built-in mechanizm in Bash, which is faster and a bit more convenient to use. Since we know that everything between $[, and ] is treated as an expression, we don't need to precede the variables with $. Similarily, we do not need to secure * from treating it like a pattern.

num1=2
num2=3
echo $[num1 + num2]
5
jedi
  • 439
5
echo `expr $a + $b`   
echo `expr $a - $b`   
echo `expr $a \* $b`   
echo `expr $a / $b`   

Note the \ before the * (for multiplication), the whole expression has to be within the backquotes `.

perror
  • 3,239
  • 7
  • 33
  • 45
Himani
  • 61
  • 1
    expr is not necessary, and it's never necessary to capture the standard output of a command just to write it back to standard output. – chepner Nov 01 '15 at 18:07
2

minimalist

total=0
((total+=qty))
geekzspot
  • 121
  • 4
2

Based on the sequence of inputs you request from the user, it seems you are using reverse polish notation.

echo "First number please"
read num1
echo "Second number please"
read num2
echo "Operation?"
read op

You may do better just to use dc (desk calculator) directly, since that is what it is for.

DESCRIPTION
       Dc is a reverse-polish desk calculator which supports unlimited pre-
       cision arithmetic.

Example session using dc:

$ dc
1 2 + p    # This part is typed; the result comes next.
3
q  # This is also typed.
$

Or, non-interactively:

$ dc -e '1 2 + p'
3
$
Wildcard
  • 36,499