I've got two strings
str1="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5"
str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2"
result=` expr $str1`
returns a correct value, while
result=` expr $str2`
expr: syntax error
The following will produce wrong results:
str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2" expr $str2
The problem is that the shell considers
* to be a wildcard file glob and will replace it with a list of files in the current directory. This is not what you want.
expr is archaic. A more modern solution would use the shell's
$((...)) form for arithmetic:
$ str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2" $ echo "$((str2))" 15
The shell only does integer arithmetic. If you actually wanted floating-point accurate results (which happen to be the same here), use
$ echo "$str2" | bc -l 15.00000000000000000000
$str2 is enclosed in double-quotes to prevent shell mischief.
When you expand a variable outside of double quotes, as in
expr $str2, the following things happen:
For example, the value of your variable contains the word
*, which is replaced by the list of file names in the current directory.
Generally speaking, always put double quotes around variable substitutions and command substitutions:
"`stuff`". See Why does my shell script choke on whitespace or other special characters? Only leave out the quotes if you know and understand why you need to leave out the quotes.
In this case, you need to have step 2 (splitting) happening, because
expr needs the operators and operands in separate arguments. But step 3 (treating each word as a filename wildcard pattern) must not happen. You can do this by turning off globbing:
result=`set -f; expr $str2`
In ksh or bash, use an array instead of a string — but in these shells you wouldn't have any use for
Unless you need your script to be portable to ancient Bourne shells, you don't need to use
expr. Arithmetic expressions are a standard POSIX feature.
¹ The separator characters can be configured via the