2
operation () {
   operator=${exp:1:1} # 2nd character / 1st is ${words:0:1} 

   # Read into an array as tokens separated by IFS
   IFS="$operator"
   read -ra array <<< "$exp" # -ra = raw input array
   a=array[0]
   b=array[1]
   # https://www.computerhope.com/unix/bash/read.htm

   if [ "$operator" == "+" ]; then
    operation=$((a+b))
   fi
   if [ "$operator" == "-" ]; then
    operation=$((a+b)) # => ' 1'
    operation=`expr a-b` # => ' 1'
   fi
   if [ "$operator" == "*" ]; then
    operation=$((a*b))
   fi
   if [ "$operator" == "/" ]; then
    operation=$((a/b))
   fi
   # https://www.tutorialsandyou.com/bash-shell-scripting/bash-arithmetic-operations-11.html
   echo $((operation))
}
exp='2-3'
operation $exp 

Everything(almost) works fine, just when making the subtraction operation=$((a+b)) or operation=`expr a-b` I cannot print in anyway minus('-') instad of space(' '), the (-) sign it is been replaced by space. In this example I get ' 1' instead of '-1'.

Why is this happening?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Diego Mota
  • 21
  • 2
  • 1
    `expr a-b` is not the same as `expr "$a" - "b"`. Why didn't you use `$((a - b))` for subtraction? – chepner Dec 20 '20 at 23:38
  • I am newbe, thank you for your useful comment =). I have been having problems understanding differences among that kind of expressions. But I am improving,. – Diego Mota Dec 23 '20 at 16:52

4 Answers4

0

use space around - :

exp=' 2 - 3 '

or

operation = expr a - b

or

COUNT="expr $FIRSTV - $SECONDV"

also see this [link]1

Darwin
  • 1,695
  • 1
  • 19
  • 29
0

I guess you meant to use - if operator is a minus sign:

if [ "$operator" == "-" ]; then
    operation=$((a - b)) # => ' 1'
fi

There are 2 problems with this script. First, arrays elements are not referenced like array[0] is in C but ${name[subscript]} as it says in man bash:

Any element of an array may be referenced using ${name[subscript]}.

So it should be:

a=${array[0]}
b=${array[1]}

Second, $((var)) should only be used for arithmetic. If you want to print contents of variable just do:

echo "$operation"

All in all, your script should be:

#!/usr/bin/env bash

operation () {
    operator=${exp:1:1} # 2nd character / 1st is ${words:0:1}

    # Read into an array as tokens separated by IFS
    IFS="$operator"
    read -ra array <<< "$exp" # -ra = raw input array
    a=${array[0]}
    b=${array[1]}
    # https://www.computerhope.com/unix/bash/read.htm

    if [ "$operator" == "+" ]; then
        operation=$((a+b))
    fi
    if [ "$operator" == "-" ]; then
        operation=$((a - b))
    fi
    if [ "$operator" == "*" ]; then
        operation=$((a*b))
    fi
    if [ "$operator" == "/" ]; then
        operation=$((a/b))
    fi
    # https://www.tutorialsandyou.com/bash-shell-scripting/bash-arithmetic-operations-11.html
    echo "$operation"
}
exp='2-3'
operation $exp

Usage:

$ ./script.sh
-1
Arkadiusz Drabczyk
  • 11,227
  • 2
  • 25
  • 38
  • I really apologize, I copy/pasted your code and didn't work, maybe there is another situation with my bash installation or something, but thank you very much. =) – Diego Mota Dec 23 '20 at 17:09
  • @DiegoMota: what do you mean by `didn't work`? – Arkadiusz Drabczyk Dec 23 '20 at 17:09
  • @DiegoMota: it works well for me with Bash 5.0.18 and Bash 5.0.3. Make sure you copied it correctly. How do you run it? – Arkadiusz Drabczyk Dec 23 '20 at 17:21
  • I will check my bash version, I have a file named arithmeticOperations.sh with exactly the same code that I posted. This problem is related to this link (https://www.hackerrank.com/challenges/bash-tutorials---arithmetic-operations/problem) and I am trying to solve it according to it. As I told you, I will check my bash version. I run it using 'bash arithmeticOperations.sh'. – Diego Mota Dec 23 '20 at 17:43
0

We're missing some context here:

  • This a=array[0] is only correct if declare -i a.
  • What is exp?

But the problem is a simple matter of lack of quoting:

$ IFS="-"
$ operation="-6"
$ echo $((operation))
 6
$ echo "$((operation))"
-6

This is entirely due to the IFS value. bash gets echo -6 and translates that into echo "" 6 with the empty string to the left of the - delimiter.

Within quotes, word splitting is not performed.

Behaviour documented in 3.5.7 Word Splitting in the manual.


You can set IFS only for the duration of the read command so it does not affect the rest of the script:

$ exp="4-5"
$ IFS=- read -ra array <<<"$exp"
$ declare -p array
declare -a array=([0]="4" [1]="5")
$ printf "%q\n" "$IFS"
$' \t\n'
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • I need a little more time to research on your answer, as I am having problems understanding it. I thank you very much for it, and will write in a couple of days (after research) with some comment. – Diego Mota Dec 23 '20 at 17:51
  • Add this page to your research list: https://unix.stackexchange.com/q/171346/4667 -- it focuses on the security implications of quoting, but the intro links to several other questions that are about quoting. – glenn jackman Dec 23 '20 at 19:59
0
  1. I remove this line operation='expr a-b' # => ' 1'
  2. In this line operation=$((a+b)) # => ' 1' you must use - instead + :
  3. For output use "" around the variables:

echo "$((operation))"

This code work properly:

operation () {
   operator=${exp:1:1} # 2nd character / 1st is ${words:0:1} 

   # Read into an array as tokens separated by IFS
   IFS="$operator"
   read -ra array <<< "$exp" # -ra = raw input array
   a=array[0]
   b=array[1]
   
   # https://www.computerhope.com/unix/bash/read.htm

   if [ "$operator" == "+" ]; then
    operation=$((a+b))
   fi
   if [ "$operator" == "-" ]; then
    operation="$((a-b))"
   fi
   if [ "$operator" == "*" ]; then
    operation=$((a*b))
   fi
   if [ "$operator" == "/" ]; then
    operation=$((a/b))
   fi
   # https://www.tutorialsandyou.com/bash-shell-scripting/bash-arithmetic-operations-11.html
   echo "$((operation))"
}
exp='2-3'
operation $exp 
Darwin
  • 1,695
  • 1
  • 19
  • 29