Configuration Information [Automatically generated, do not change]:
Machine: i686
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i686' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall
uname output: Linux m41 4.2.0-34-generic #39-Ubuntu SMP Thu Mar 10 22:11:49 UTC 2016 i686 i686 i686 GNU/Linux
Machine Type: i686-pc-linux-gnu
Bash Version: 4.3
Patch Level: 42
Release Status: release
Description:
Odd behaviour when an undefined variable is used in arithemetic _expression_.
((++F[word]==M)) increments both F[word] AND M
But not always.
When M is null, M seems to be treated as 0 (as expected)
When M is assigned an integer value of an integer associative array element,
something goes wrong.
(just a guess, since as you will see, this is complex to demonstrate)
This can happen when M=1 but usually when M=2.
Repeat-By:
#!/bin/bash
p(){ # print variables
printf "F[%s]=[%d] M=[%d] I=[%s]\n" "$1" $((F[$1]*1)) $((M*1)) "$I"
}
t(){ # iterate - part of a program that counts word frequency and tracks most frequent word
p $W
# M should not change here
((++F[$W]==M))&&I= # pre-increment F[$W]. If equal to Max then I=NULL
p $W
# but sometimes, it does!
((F[$W]>M))&&M=F[$W]&&I=$W # if F[$W]>Max then Max=F[$W]
p $W
}
unset F
unset X
unset M
unset W
unset I
W="word"
echo setup
# it always fails, but at different iterations!
# why does it fail ever?????
# an example run
# run 3
#+ t
#+ p word
#+ printf 'F[%s]=[%d] M=[%d] I=[%s]\n' word 2 2 ''
# here, M=2
#F[word]=[2] M=[2] I=[]
#+ (( ++F[word]==M ))
#+ I=
#+ p word
#+ printf 'F[%s]=[%d] M=[%d] I=[%s]\n' word 3 3 ''
# without changing M, it is now 3!!!!!!
#F[word]=[3] M=[3] I=[]
#+ (( F[word]>M ))
#+ p word
#+ printf 'F[%s]=[%d] M=[%d] I=[%s]\n' word 3 3 ''
#F[word]=[3] M=[3] I=[]
#+ set +x
# only when setting M from F[$W] or F[word] causes it to fail at iteration 2
declare -iA F; F[word]=1; M=F[word] # fails run 2
#declare -iA F; F[$W]=1; M=F[$W] # fails run 2
# all other ways to initialise M fail at iteration 3
#declare -iA F; declare -iA X; F[$W]=1; X[dog]=1; M=X[dog] # fails run 3
#declare -iA F; declare -iA X; F[$W]=1; X[$W]=1; M=X[$W] # fails run 3
#declare -iA F; F[$W]=1; M=1 # fails run 3
#declare -iA F; F[$W]=1; M="1" # fails run 3
#declare -iA F; F[$W]=1; M=$((1*1)) # fails run 3
#declare -iA F; F[$W]=1; ((M=1)) # fails run 3
#declare -iA F; F[$W]=1; M=${F[$W]} # fails run 3
I=$W
p $W
echo run 2
t
echo run 3
set -x
t
set +x
echo run 4
t
Fix:
declare -i M
This seems to 'fix' this.