This reorder function is meant to swap values of a two-element array if unordered. Bash and ksh produce reversed results. mksh and zsh do as expected.
#!/usr/bin/env bash [[ -n ${ZSH_VERSION+_} ]] && emulate ksh function reorder { (( x[1] < x && (x=x[1], x[1]=$x) )) echo "${x[@]}" } x=(123 456) reorder x=(456 123) reorder eval echo '${'{BA,K,Z}SH_VERSION\} # vim: ft=sh : $ bash ./reorder 456 123 123 456 4.2.37(1)-release $ ksh ./reorder 123 456 456 123 Version AJM 93u+ 2012-06-28 $ mksh ./reorder 123 456 123 456 @(#)MIRBSD KSH R40 2012/09/01 $ zsh ./reorder 123 456 123 456 5.0.0 The Ksh issue seems to be that an explicit x[0] is needed (it's a slightly outdated dev build), but I can't figure out why Bash is doing this. No parameter expansion in the arithmetic does the same: function reorder2 { _=$x let '(x[1] < x) && (x=x[1], x[1]=_)' echo "${x[@]}" } Some variations crash: $ bash -c 'function reorder { (( x[1] < x[0] && (x=x[1], x[1]=$x) )); echo "${x[@]}"; }; x=(123 456); reorder; x=(456 123); reorder' Segmentation fault $ bash -c 'function reorder { (( (x > x[1]) && (x=${x[1]}, x[1]=$x) )); echo "${x[@]}"; }; x=(123 456); reorder; x=(456 123); reorder' 123 456 Segmentation fault The second issue is that Bash tries to resolve arithmetic variables when evaluation should never reach them. Some methods of short-circuiting do work, e.g. to populate an array: $ n=0 a=a[n]=n=(n+1)%10,a; ((a)); echo "${a[@]}" # Bash 0 1 2 3 4 5 6 7 8 9 However, In this case, `a' should be protected by `&&'. The same occurs with `||' and `x?y:z'. $ zsh -c 'emulate ksh; typeset -a a; n=0 a="(a[n]=n++)<7&&a"; ((a)); echo "${a[@]:1}"' # max depth == 256 0 1 2 3 4 5 6 7 $ ksh -c 'n=0 a="(a[n]=++n)<7&&a[0]"; ((a[0])); echo "${a[@]:1}"' # max depth == 8 1 2 3 4 5 6 7 $ bash -c 'n=0 a="(a[n]=++n)<7&&a[0]"; ((a[0])); echo "${a[@]:1}"' # max depth == 1024 bash: n: expression recursion level exceeded (error token is "n") $ bash -c 'n=0 a="(a[n]=n++)<7&&a"; ((a)); echo "${a[@]:1}"' bash: (a[n]=n++)<7&&a: expression recursion level exceeded (error token is "n++)<7&&a") 0 1 2 3 4 5 6 7 The last one both gets the right answer and throws an error... weird. It appears the mksh method is to keep track of which variables have been visited and error if any are referenced twice, rather than counting the arithmetic evaluator stack depth, so this isn't possible in that shell. -- Dan Douglas
signature.asc
Description: This is a digitally signed message part.