Home > Enterprise >  Why can I refer to a variable inside (( )) without the $ symbol?
Why can I refer to a variable inside (( )) without the $ symbol?

Time:08-06

In ABS guide, I could see below snippet

var1=5
var2=4

if (( var1  > var2 ))
then
echo "$var1 is greater than $var2"
fi

I am not able to understand, why we don't need $ symbol. I added $ symbol, shellcheck shows "$ symbol is not necessary on arithmetic variables".

I am still not able to understand how that dereferencing of var1 and var2 works...

CodePudding user response:

Expressions inside ((...)) are evaluated in arithmetic context. Strings which can be variable names are considered as variables whose values are integers, since evaluating these strings as literal strings makes no sense in arithmetic context. These considerations are also valid for C style for loops: in for ((i = 0; i < 10; i)), preceding i with $ is not necessary (but it may be necessary, depending on the context, within the body of the loop).

CodePudding user response:

(( ... )) follows the same evaluation rules as defined in the POSIX specification for arithmetic expressions. (The main difference is ((...)) produces an exit status reflecting if the result is zero/nonzero, while $((...)) produces the result as a string.) In particular:

If the shell variable x contains a value that forms a valid integer constant, optionally including a leading <plus-sign> or <hyphen-minus>, then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value.

The shell variable var1 contains an integer constant, so $((var1)) and $(($var1)) are equivalent. This holds recursively as well.

Various shells seem to treat variables that refer to variables differently. Nothing in the POSIX wording seems to require the following kind of recursive evaluation, though both bash and dash do:

$ foo=bar
$ bar=5
$ echo $((foo))  # foo/$foo evaluates to bar, which contains an integer constant
5

bash seems to take it a step further, allowing any string to expand, followed by an attempt to evaluate the result as an arithmetic expression.

$ foo="x   3"
$ x=5
$ echo $((foo))  # foo evaluates to x   3, which evaluates to 5   3
8

but in dash:

$ foo="x 3"
$ x=5
$ echo $((foo))
dash: 3: Illegal number: x 3

CodePudding user response:

It's documented in the manual in 6.5 Shell Arithmetic. It says

Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax.

This features makes arithmetic expressions so much easier to read.

Interestingly, you can also refer to array elements like this as well

values=(42 54) i=0 j=1

echo $(( values[i]   values[j] ))   # => 96

Other places you don't need $ (i.e. other arithmetic "contexts"):

  • For numerically-indexed arrays, the index (${values[i]} not ${values[$i]})
  • the offset and length parts of the ${var:offset:length} parameter expansion.

CodePudding user response:

You don't need the $ if it's inside the (( )) for doing arithmetic.

I am still not able to understand how that dereferencing of var1 and var2 works

bash parses things differently inside the (( )), undoubtedly because it makes it much easier to read complex arithmetic expressions without the $.

  •  Tags:  
  • bash
  • Related