I've got two strings
str1="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5"
and
str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2"
The command
result=` expr $str1`
returns a correct value, while
result=` expr $str2`
returns expr: syntax error
I've got two strings
str1="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5"
and
str2="( 1 + 2 + 3 + 4 + 5 ) / 3 + 5 * 2"
The command
result=` expr $str1`
returns a correct value, while
result=` expr $str2`
returns 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 bc
:
$ echo "$str2" | bc -l
15.00000000000000000000
Note that $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"
, "`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 expr
.
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.
result=$(($str2))
¹ The separator characters can be configured via the IFS
variable.
expr "$str2"
. Or use your shell:str='(1+2+3+4+5)/3+5'; echo "$(($str))" "$(($str*2))"
– mikeserv Apr 09 '15 at 22:585 * 2
or5 \* 2
instr2
? This isn't clear from what you posted. Please take a minute to go familiarize yourself with the formatting features on this site; you can see a guide by browsing through the buttons above the edit box and reading the help available by clicking on the?
button. – Gilles 'SO- stop being evil' Apr 09 '15 at 23:13