ksh vs. bash

We all know that our shell of choice (c'on, admit it :-)) is "too big and too slow" (quote from its manpage). But I was surprised to see *how* slow it was for this particular operation:

Update: Thanks to an observing commenter I had to find out that 'expr' is NOT a shell builtin but a simple binary. I always wondered *if* it was a shell builtin and always wondered if scripts with 'expr' would be portable and all but I never got around to do just 'which expr'. Damn. Anyway, here are the updated results now. Thanks again Roland for pointing this out! The gap between bash and ksh is not so big any more, although it's still visible:

# cat count.sh
i=1
while [ "$i" -lt 10000000 ]; do
        ((i++))
done

# for i in ksh zsh pdksh mksh bash; do (echo "SHELL: $i"; time $i count.sh); done
SHELL: ksh
real	0m45.196s
user	0m44.676s
sys	0m0.070s

SHELL: zsh
real	1m13.755s
user	1m5.651s
sys	0m7.402s

SHELL: pdksh
real	1m7.300s
user	1m6.013s
sys	0m0.092s

SHELL: mksh
real	1m8.922s
user	1m8.013s
sys	0m0.091s

SHELL: bash
real	3m10.721s
user	3m0.016s
sys	0m6.372s
This was done with ksh from AT&T Research (1993-12-28), zsh 4.3.4, PDKSH v5.2.14, MIRBSD KSH R32 and GNU bash 3.2.39(1) on a MacMini.

Update #2: as pointed out in the comment section, "(())" should be faster, so let's try again:
$ cat count.sh 
i=1
while (( i++ < 10000000 )); do
        :
done
$ for i in ksh zsh pdksh mksh bash; do echo "SHELL: $i"; time $i count.sh; done
SHELL: ksh
real    1m59.642s
user    1m58.340s
sys     0m0.012s

SHELL: zsh
real    3m34.747s
user    3m4.588s
sys     0m25.616s

SHELL: pdksh
real    4m15.224s
user    4m10.056s
sys     0m0.028s

SHELL: mksh
real    4m48.835s
user    4m43.480s
sys     0m0.036s

SHELL: bash
real    10m9.914s
user    9m52.724s
sys     0m4.072s
This was done with ksh-93s+ from AT&T Research (2008-01-31), zsh 4.3.10, PDKSH v5.2.14, MIRBSD KSH R39c and GNU bash 4.1.5(1) on a PowerBook G4 (M9691LL/A) (throttled to 750MHz).