1
#!/bin/bash
if [ $# -lt 3 ] ;then
        echo "USAGE : calculate.sh VAR1 OPERATOR VAR2"
exit 1
fi
VAR1=$1
OP=$2
VAR2=$3
if [ $OP = '+' ];then
        echo "$VAR1+$VAR2=$[$VAR1+$VAR2]"
        exit 0
elif [ $OP = '-' ];then
        echo "$VAR1-$VAR2=$[$VAR1-$VAR2]"
        exit 0
elif [ $OP = '*' ];then
        echo "$VAR1*$VAR2=$[$VAR1*$VAR2]"
        exit 0;
else
        echo "$VAR1/$VAR2=$[$VAR1/$VAR2]"
fi

The above is the content of calculate.sh.

If I use +, -, or /, I get the correct answer, but when I use *, it reports an error:

 kdyzm@kdyzm:~/scripts$ ./calculate.sh 2 + 3 
 2+3=5
 kdyzm@kdyzm:~/scripts$ ./calculate.sh 2 - 3 
 2-3=-1
 kdyzm@kdyzm:~/scripts$ ./calculate.sh 2 * 3
 ./calculate.sh: line 21: 2/command.sh: syntax error: invalid arithmetic operator (error token is ".sh")
 kdyzm@kdyzm:~/scripts$ ./calculate.sh 2 / 3 
 2/3=0
 kdyzm@kdyzm:~/scripts$

How can I resolve this problem?

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
dyzm k
  • 43
  • 8

3 Answers3

2

You have to quote the arguments when you want to pass a *:

./calculate.sh 2 \* 3 
ceving
  • 21,900
  • 13
  • 104
  • 178
2

The * character in bash is special and is returning a list of files. So instead of 2 * 3 you are getting a lot of files in addition to what you expect.

If you do an echo "$@" at the top of your script you'll see the actual parameters. On my system you get:

2 dump.xsl t.sh test.awk test.c test.cpp test.py test.sh 3

So my $var2 ends up being t.sh and causes a syntax error. If you want to pass in a reserved character you need to quote it: ./calculate.sh 2 \* 3

AlG
  • 14,697
  • 4
  • 41
  • 54
  • In addition to this ,i have to put double quotes around $OP ,otherwise the problem is still. – dyzm k Feb 02 '16 at 12:53
0

The problem was as pointed by others the fact than the character * is interpreted by your shell, be it in your terminal or your script. You must use backslash to make the shell understand it is really the character '*'.

Here is a complete solution. Please, notice the condition [ $# -ne 3 ] rather than [ $# -le 3 ]and the condition [ $OP = '\*' ] rather than else. It is very bad practice to let unasked cases to go through. Doing so may cause hard to debug situations as you have now experienced.

#!/bin/bash

if [ $# -ne 3 ]
then
        echo "USAGE : calculate.sh VAR1 OPERATOR VAR2"
    exit 1
fi

VAR1=$1
OP=$2
VAR2=$3

if [ $OP = '+' ]
then
        echo "$VAR1+$VAR2 = "$(expr $VAR1 + $VAR2)
elif [ $OP = '-' ]
then
        echo "$VAR1-$VAR2 = "$(expr $VAR1 - $VAR2)
elif [ $OP = '\*' ]
then
        echo "$VAR1*$VAR2 = "$(expr $VAR1 \* $VAR2)
elif [ $OP = '/' ]
then
        echo "$VAR1/$VAR2 = "$(expr $VAR1 / $VAR2)
else
    echo "Operator must be +-*/"
    exit 1
fi
exit 0

Which gives :

adrien@adrienLT:~/Documents/PEV$ ./calculate.sh 6 '+' 5
6+5 = 11
adrien@adrienLT:~/Documents/PEV$ ./calculate.sh 6 '-' 5
6-5 = 1
adrien@adrienLT:~/Documents/PEV$ ./calculate.sh 6 '\*' 5
6*5 = 30
adrien@adrienLT:~/Documents/PEV$ ./calculate.sh 6 '/' 5
6/5 = 1
adrien@adrienLT:~/Documents/PEV$ ./calculate.sh 6 '*' 5
./calculate.sh: line 13: [: too many arguments
./calculate.sh: line 17: [: too many arguments
./calculate.sh: line 21: [: too many arguments
./calculate.sh: line 25: [: too many arguments
Operator must be +-*/
adrien@adrienLT:~/Documents/PEV$ ./calculate.sh 6 * 5
USAGE : calculate.sh VAR1 OPERATOR VAR2

Not perfect but much easier to debug.

Adrien Horgnies
  • 691
  • 4
  • 11
  • Though a `case` statement would seem more natural here. You forgot `exit 0` in the multiplication case. – tripleee Feb 03 '16 at 05:33
  • The requirement to quote *and* backslash the asterisk is a bug. One or the other should suffice. This can be fixed by properly quoting `$OP` everywhere; or, as suggested above, with a `case` statement. See also http://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-variable – tripleee Feb 03 '16 at 05:34
  • @tripleee I began from original poster question and tried to get something similar. I added exit 0 at the end of the script thank to your recommandation. Otherwise, I would just send arguments to expr. Quoting and escaping the asterisk is my way of coding, it's to your preference. I find it easier to reread. – Adrien Horgnies Feb 03 '16 at 10:05
  • Very much belated addition: to avoid the error message `[: too many arguments`, just (properly) quote `"$OP"` (and of course `"*"`) in the `elif` (eg `elif [ "$OP" = "*" ] ...` or avoid the problem altogether by using the modern bash double-bracket syntax feature: `elif [[ $OP = * ]] ...` – michael Sep 06 '18 at 05:49