3

I found the following statement in the bash manpage (version 4.2) under the Arithmetic Evaluation section.

A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.

In the Advanced Bash Scripting Guide, there is a page with the following comment.

#  Bash (usually) sets the "integer value" of null to zero
#+ when performing an arithmetic operation.
#  But, don't try this at home, folks!
#  It's undocumented and probably non-portable behavior.

Here are examples of this behavior:

$ foo=
$ let 'foo += 5'
$ echo $foo
5
$ unset foo
$ let 'foo += 2'
$ echo $foo
2

Is it safe to assume that bash will substitute null variables with 0? Could assuming so result in code that is unportable between bash versions?

2

From the manual:

A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.

I'm not aware of this having changed, and this is also the case in pdksh, ksh93, dash and zsh, but POSIX doesn't specify the behavior.

Note that if set -o nounset (a.k.a. set -u) is in effect, $((a)) or ((a+=1)) causes an error if a is unset (in bash and ksh93 but not in dash, pdksh or zsh).

Note also that this only applies when you use the parameter directly in the arithmetic expression $((a+1)), not when you use parameter substitution $(($a+1)). Contrast:

$ unset a
$ echo $((1 - a + 2))   # 1 - 0 + 2
3
$ echo $((a - $a + 2))  # 1 - (+2)
-1
3

Yes, bash arithmetic expansion is borrowed from ksh, and that has been the documented way in ksh since the 80s.

Note however, that in POSIX arithmetic expansion as in $((x * 2)), the behavior is unspecified (by POSIX) unless $x contains a decimal numerical constant (as in, 2 and -2 are OK, but the empty string or 1+1 are not) which means that you can't make that assumption in POSIX sh scripts.

Also beware of (in bash, ksh, zsh at least):

$ echo $((2*$foo-2)) # actually $((2*-2))
-4
$ echo $((2*foo-2))  # actually $((2*0-2))
-2
2

It is probably safe to assume that bash will substitute null variables with 0 on any reasonably recent system.

As it is documented in the manpage for bash 4.2, it is certainly documented behaviour as of at least that version. As it is described as behaving that way (but undocumented) in the Advanced Bash Scripting Guide, you can expect that behaviour in whatever version of bash was available when that was written. It likely goes back to very early versions of bash.

If you want to be ABSOLUTELY strict, however, you will need to check the documentation for all the bash versions you want to support, and you can't make any assumptions about any of those versions which do not explicitly document the behaviour.

I don't think you need to be absolutely strict, but if you aren't taking any chances, you can use foo=${foo:-0} to explicitly set undefined variables to 0 before using them. Example:

foo=1

foo=${foo:-0}
bar=${bar:-0}

echo "before math: foo=$foo, bar=$bar"
let 'foo += 2'
let 'bar += 2'
echo "after math: foo=$foo, bar=$bar"

Output:

before math: foo=1, bar=0
after math: foo=3, bar=2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy