I've been troubleshooting a ksh93 script I wrote today and have narrowed it down to the root cause. but I don't understand why?
so, i've written the following script to demonstrate the problem i found today:
#!/bin/ksh
method=$1
FILE_LIST=( $(find /someplace -type f -printf "%T@\t%p\n" 2>/dev/null | sort -r | awk '{print $2}') )
print "found ${#FILE_LIST[*]} files."
typeset -li counter=0
for file in ${FILE_LIST[*]}
do
case $method in
0)
[[ -f $file ]] \
&& (( counter++ )) \
&& continue
;;
1)
if [[ -f "$file" ]] ; then
(( counter++ ))
continue
fi
;;
*)
print "don't know that method"
exit 1
;;
esac
print "should never get here: $file"
done
print "counter=$counter"
the code for when method=0 or 1 provides different results. I *thought* it would be the same, and I don't understand why it isn't:
$ ./t60.ksh 1
found 106 files.
counter=106
$ ./t60.ksh 0
found 106 files.
should never get here: /someplace/.t60.ksh.swp
counter=106
The ".t60.ksh.swp" file is simply the 1st element of the FILE_LIST array. Why does method=0 result in execution of the "should never get here" line once? (and why only once?) I was expecting it to have the same result as method=1.
After running ((counter++)), the exit code is 1, not zero, and hence the continue statement is not executed. The reason is that the value of counter++ is what is stored in counter BEFORE it is incremented, i.e zero. If the value of the expression is zero, the exit code of the ((....)) command is 1. If the value of the expression is not zero, the exit code of the ((....)) command is 0.
The AND operator && in the form of command1 && command2 says that command2 is executed only if command1 returns an exit status of zero. (( counter++ )) will not return zero so continue is not hit.
With method 1 the continue will be executed unconditionally.
To complement rovf correct explanation ..
To have expected result, altho a lot of redundant code is there, increment the variable BEFORE ++counter , instead of AFTER counter++
Or just leave out the ((...)) syntax and use counter=$((counter+1)) , which is to be used if you do not require behaviour ((...)) offers.
For the sake of clarity i suggest you stay away from keywords like "continue" and "break" as long as possible and use them only as a very last resort. You see, both are basically variants of the GOTO and we know how we feel about GOTO, don't we?
In your example code i don't even understand what the "continue" should accomplish: the case-part already finishes at this point and the next iteration of the for-loop will start anyway, so the difference is perhaps the time it takes to execute the "fi", the ";;" and the "next" - is it only me or should that really be negligible?