0

I have the following shell script that sums up all the arguments passed to it (space separated):

sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

I have saved it as SumAll.sh. So, its supposed to function as follows:

sh SumAll.sh 2 4 6 8
20

or

bash SumAll.sh 1 -2 3 -3
-1

Both work on my local machine (MacBook), but when I try the same in a linux server, running the script with bash works, but with sh does not work. I get the following error:

sum: '+=': No such file or directory
sum: arg: No such file or directory

Why is that? And how do I fix it?

2 Answers2

4

Arithmetic evaluation with (( ... )) is an extension to the standard POSIX shell syntax that bash implements. Most sh shells would not understand that syntax.

Use an arithmetic substitution instead: sum=$(( sum + arg ))

In a shell that does not implement the non-standard (( ... )), your (( sum += arg )) command will be interpreted as a nested subshell, calling the command sum with the two arguments += and arg.

On macOS, sum is a utility that calculates checksums of files (see man sum), and the files += and arg can not be found (which is why you get that particular error).

Kusalananda
  • 333,661
  • 1
    The follow-on question is https://unix.stackexchange.com/q/250913/5132 . The Bourne Again, Z, and Korn shells all have ((…)). The Almquist and Bourne shells, the former being the most likely sh given its use on Debian and its derivatives, do not. https://unix.stackexchange.com/a/149916/5132 – JdeBP May 12 '20 at 07:44
  • @JdeBP and that comment is the correct answer for "why is that" - linux default sh is most likely symlink to dash – alecxs May 31 '20 at 11:57
2

Use shellcheck.

Example using your script:

#!/bin/bash
sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

result:

$ shellcheck myscript

Line 6:
echo $sum
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$sum"

As you can see, this works, but if you use sh like you did previously:

#!/bin/sh
sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

result:

$ shellcheck myscript

Line 4:
    (( sum += arg ))
    ^-- SC2039: In POSIX sh, standalone ((..)) is undefined.

Line 6:
echo $sum
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$sum"

This doesn't work here, because of the error SC2039 (which is the first one in this instance).

While obvious, you need to remember that sh and bash have some difference in syntax. So that's the main reason it doesn't work. (as @kusalananda detailed in his answer)

You should also use the -x or debug flag more often, so you can see what and at which moment your script fail.

For more infos and tips on bash and shell scripting, i recommend:

-Bash's Unofficial Wiki

-Bash Bible