Where does recursive variable expansion occur in bash / shell numeric contexts?
The POSIX specification points to the Arithmetic Extension , which
[i] f shell variable x contains a value that forms a valid integer constant, optionally including a plus or minus sign, then the arithmetic expansions "$ ((x))" and "$ ((x)),)" must return the same value.
It's a sensible shortcut and cleans up complex expressions pretty well.
bash (versions 3.2.25(1)-release
from CentOS 5 and 4.3.33(1)-release
from debian unstable) as well as ksh ( Version AJM 93t+ 2010-06-21
from CentOS 5) all seem to go one step further than that.
All of them recursively expand variables found in arithmetic expansion (and numeric contexts in those [[
resulting from using numeric operators).
In particular:
$ set -x
$ bar=5
+ bar=5
$ foo=bar
+ foo=bar
$ [ foo -gt 4 ]; echo $?
+ '[' foo -gt 4 ']'
-bash: [: foo: integer expression expected
+ echo 2
2
$ [[ foo -gt 4 ]]; echo $?
+ [[ foo -gt 4 ]]
+ echo 0
0
$ [[ foo -eq 0 ]]; echo $?
+ [[ foo -eq 0 ]]
+ echo 1
1
$ [[ foo -eq 5 ]]; echo $?
+ [[ foo -eq 5 ]]
+ echo 0
0
$ (( foo == bar )); echo $?
+ (( foo == bar ))
+ echo 0
0
$ (( foo == 1 )); echo $?
+ (( foo == 1 ))
+ echo 1
1
Where did this behavior come from and why would it be desirable?
Uses [[
instead is [
clearly less safe when used with numeric operators, because invalid values and typographical errors come from script errors to be silent (but probably wrong).
Edit: As a side question, if anyone knows when this "feature" was added to bash / etc. I would also be interested to know this.
source to share
This is worse than you think. The value of a variable is recursively treated as an arithmetic expression:
$ foo='bar+bar'
$ echo $((foo))
10
The bash manual section on Shell Arithmetic says:
The value of a variable is evaluated as an arithmetic expression when it is referenced, or when a value is assigned to a variable that has been assigned an integer attribute using 'declare -i.
The last part means that you can:
$ declare -i int
$ int=bar+bar
$ echo $int
10
Please note that this does not violate the above specification. It only says what to do if the value of the variable is an integer constant. It does not tell you what to do if the value is something else, which leaves it open to implementations to add such extensions. The Bash Hackers Wiki explains this:
If the variable has no value that looks like a valid expression (numbers or operations), the expression is reused to refer to, for example named parameters
If the possible extension is not a valid expression, you will receive an error message:
$ foo='a b'
$ bar=foo
echo $((bar))
bash: a b: syntax error in expression (error token is "b")
So, if your variable contains random things, it might throw an error. But if it only contains one word, that is valid variable syntax, which will evaluate as 0
if the variable is not set.
source to share