how can I add (subtract, etc.) two numbers with bash?

  • 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").

    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/

    +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 :)

  • goldilocks

    goldilocks Correct answer

    7 years ago

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

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

    You can assign from that (sans echo):

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

    There is also expr:

    expr $num1 + $num2
    

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

    Or even directly `echo $(($num1$op$num2))` without involving `case`.

    There's no `case` involved here.

    No, but you used literal `+`, so will need the `case` outside to handle the subtraction separately.

    @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 `*`.

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

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

    @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?

    Only expressions `$((...))` are defined by POSIX; stand-alone statements `((...))` are a `bash` extension.

    `$[...]` 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 Thx. Edited.

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM