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.

+3


source to share


1 answer


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.

+2


source







All Articles