1 ## compare_shells: bash dash mksh zsh
2
3
4 # Interesting interpretation of constants.
5 #
6 # "Constants with a leading 0 are interpreted as octal numbers. A leading ‘0x’
7 # or ‘0X’ denotes hexadecimal. Otherwise, numbers take the form [base#]n, where
8 # the optional base is a decimal number between 2 and 64 representing the
9 # arithmetic base, and n is a number in that base. If base# is omitted, then
10 # base 10 is used. When specifying n, the digits greater than 9 are represented
11 # by the lowercase letters, the uppercase letters, ‘@’, and ‘_’, in that order.
12 # If base is less than or equal to 36, lowercase and uppercase letters may be
13 # used interchangeably to represent numbers between 10 and 35. "
14 #
15 # NOTE $(( 8#9 )) can fail, and this can be done at parse time...
16
17 #### Side Effect in Array Indexing
18 a=(4 5 6)
19 echo "${a[b=2]} b=$b"
20 ## stdout: 6 b=2
21 ## OK zsh stdout: 5 b=2
22 ## N-I dash stdout-json: ""
23 ## N-I dash status: 2
24
25 #### Add one to var
26 i=1
27 echo $(($i+1))
28 ## stdout: 2
29
30 #### $ is optional
31 i=1
32 echo $((i+1))
33 ## stdout: 2
34
35 #### SimpleVarSub within arith
36 j=0
37 echo $(($j + 42))
38 ## stdout: 42
39
40 #### BracedVarSub within ArithSub
41 echo $((${j:-5} + 1))
42 ## stdout: 6
43
44 #### Arith word part
45 foo=1; echo $((foo+1))bar$(($foo+1))
46 ## stdout: 2bar2
47
48 #### Arith sub with word parts
49 # Making 13 from two different kinds of sub. Geez.
50 echo $((1 + $(echo 1)${undefined:-3}))
51 ## stdout: 14
52
53 #### Constant with quotes like '1'
54 # NOTE: Compare with [[. That is a COMMAND level expression, while this is a
55 # WORD level expression.
56 echo $(('1' + 2))
57 ## status: 0
58 ## N-I bash/zsh status: 1
59 ## N-I dash status: 2
60
61 #### Arith sub within arith sub
62 # This is unnecessary but works in all shells.
63 echo $((1 + $((2 + 3)) + 4))
64 ## stdout: 10
65
66 #### Backticks within arith sub
67 # This is unnecessary but works in all shells.
68 echo $((`echo 1` + 2))
69 ## stdout: 3
70
71 #### Invalid string to int
72 # bash, mksh, and zsh all treat strings that don't look like numbers as zero.
73 shopt -u strict_arith || true
74 s=foo
75 echo $((s+5))
76 ## OK dash stdout-json: ""
77 ## OK dash status: 2
78 ## OK bash/mksh/zsh/osh stdout: 5
79 ## OK bash/mksh/zsh/osh status: 0
80
81 #### Invalid string to int with strict_arith
82 shopt -s strict_arith || true
83 s=foo
84 echo $s
85 echo $((s+5))
86 echo 'should not get here'
87 ## status: 1
88 ## STDOUT:
89 foo
90 ## END
91 ## OK dash status: 2
92 ## N-I bash/mksh/zsh STDOUT:
93 foo
94 5
95 should not get here
96 ## END
97 ## N-I bash/mksh/zsh status: 0
98
99 #### Integer constant parsing
100 echo $(( 0x12A ))
101 echo $(( 0x0A ))
102 echo $(( 0777 ))
103 echo $(( 0010 ))
104 echo $(( 24#ag7 ))
105 ## STDOUT:
106 298
107 10
108 511
109 8
110 6151
111 ## END
112
113 ## N-I dash status: 2
114 ## N-I dash STDOUT:
115 298
116 10
117 511
118 8
119 ## END
120
121 ## BUG zsh STDOUT:
122 298
123 10
124 777
125 10
126 6151
127 ## END
128
129 ## BUG mksh STDOUT:
130 298
131 10
132 777
133 10
134 6151
135 ## END
136
137 #### Integer constant validation
138 check() {
139 $SH -c "shopt --set strict_arith; echo $1"
140 echo status=$?
141 }
142
143 check '$(( 0x1X ))'
144 check '$(( 09 ))'
145 check '$(( 2#A ))'
146 check '$(( 02#0110 ))'
147 ## STDOUT:
148 status=1
149 status=1
150 status=1
151 status=1
152 ## END
153
154 ## OK dash STDOUT:
155 status=2
156 status=2
157 status=2
158 status=2
159 ## END
160
161 ## BUG zsh STDOUT:
162 status=1
163 9
164 status=0
165 status=1
166 6
167 status=0
168 ## END
169
170 ## BUG mksh STDOUT:
171 status=1
172 9
173 status=0
174 status=1
175 6
176 status=0
177 ## END
178
179 #### Newline in the middle of expression
180 echo $((1
181 + 2))
182 ## stdout: 3
183
184 #### Ternary operator
185 a=1
186 b=2
187 echo $((a>b?5:10))
188 ## stdout: 10
189
190 #### Preincrement
191 a=4
192 echo $((++a))
193 echo $a
194 ## STDOUT:
195 5
196 5
197 ## END
198 ## N-I dash status: 0
199 ## N-I dash STDOUT:
200 4
201 4
202 ## END
203
204 #### Postincrement
205 a=4
206 echo $((a++))
207 echo $a
208 ## STDOUT:
209 4
210 5
211 ## END
212 ## N-I dash status: 2
213 ## N-I dash stdout-json: ""
214
215 #### Increment undefined variables
216 shopt -u strict_arith || true
217 (( undef1++ ))
218 (( ++undef2 ))
219 echo "[$undef1][$undef2]"
220 ## stdout: [1][1]
221 ## N-I dash stdout: [][]
222
223 #### Increment and decrement array elements
224 shopt -u strict_arith || true
225 a=(5 6 7 8)
226 (( a[0]++, ++a[1], a[2]--, --a[3] ))
227 (( undef[0]++, ++undef[1], undef[2]--, --undef[3] ))
228 echo "${a[@]}" - "${undef[@]}"
229 ## stdout: 6 7 6 7 - 1 1 -1 -1
230 ## N-I dash stdout-json: ""
231 ## N-I dash status: 2
232 ## BUG zsh stdout: 5 6 7 8 -
233
234 #### Increment undefined variables with nounset
235 set -o nounset
236 (( undef1++ ))
237 (( ++undef2 ))
238 echo "[$undef1][$undef2]"
239 ## stdout-json: ""
240 ## status: 1
241 ## OK dash status: 2
242 ## BUG mksh/zsh status: 0
243 ## BUG mksh/zsh STDOUT:
244 [1][1]
245 ## END
246
247 #### Comma operator (borrowed from C)
248 a=1
249 b=2
250 echo $((a,(b+1)))
251 ## stdout: 3
252 ## N-I dash status: 2
253 ## N-I dash stdout-json: ""
254
255 #### Augmented assignment
256 a=4
257 echo $((a+=1))
258 echo $a
259 ## STDOUT:
260 5
261 5
262 ## END
263
264 #### Comparison Ops
265 echo $(( 1 == 1 ))
266 echo $(( 1 != 1 ))
267 echo $(( 1 < 1 ))
268 echo $(( 1 <= 1 ))
269 echo $(( 1 > 1 ))
270 echo $(( 1 >= 1 ))
271 ## STDOUT:
272 1
273 0
274 0
275 1
276 0
277 1
278 ## END
279
280 #### Logical Ops
281 echo $((1 || 2))
282 echo $((1 && 2))
283 echo $((!(1 || 2)))
284 ## STDOUT:
285 1
286 1
287 0
288 ## END
289
290 #### Logical Ops Short Circuit
291 x=11
292 (( 1 || (x = 22) ))
293 echo $x
294 (( 0 || (x = 33) ))
295 echo $x
296 (( 0 && (x = 44) ))
297 echo $x
298 (( 1 && (x = 55) ))
299 echo $x
300 ## STDOUT:
301 11
302 33
303 33
304 55
305 ## END
306 ## N-I dash STDOUT:
307 11
308 11
309 11
310 11
311 ## END
312
313 #### Bitwise ops
314 echo $((1|2))
315 echo $((1&2))
316 echo $((1^2))
317 echo $((~(1|2)))
318 ## STDOUT:
319 3
320 0
321 3
322 -4
323 ## END
324
325 #### Unary minus and plus
326 a=1
327 b=3
328 echo $((- a + + b))
329 ## STDOUT:
330 2
331 ## END
332
333 #### No floating point
334 echo $((1 + 2.3))
335 ## status: 2
336 ## OK bash/mksh status: 1
337 ## BUG zsh status: 0
338
339 #### Array indexing in arith
340 # zsh does 1-based indexing!
341 array=(1 2 3 4)
342 echo $((array[1] + array[2]*3))
343 ## stdout: 11
344 ## OK zsh stdout: 7
345 ## N-I dash status: 2
346 ## N-I dash stdout-json: ""
347
348 #### Constants in base 36
349 echo $((36#a))-$((36#z))
350 ## stdout: 10-35
351 ## N-I dash stdout-json: ""
352 ## N-I dash status: 2
353
354 #### Constants in bases 2 to 64
355 # This is a truly bizarre syntax. Oh it comes from zsh... which allows 36.
356 echo $((64#a))-$((64#z)), $((64#A))-$((64#Z)), $((64#@)), $(( 64#_ ))
357 ## stdout: 10-35, 36-61, 62, 63
358 ## N-I dash stdout-json: ""
359 ## N-I dash status: 2
360 ## N-I mksh/zsh stdout-json: ""
361 ## N-I mksh/zsh status: 1
362
363 #### Multiple digit constants with base N
364 echo $((10#0123)), $((16#1b))
365 ## stdout: 123, 27
366 ## N-I dash stdout-json: ""
367 ## N-I dash status: 2
368
369 #### Dynamic base constants
370 base=16
371 echo $(( ${base}#a ))
372 ## stdout: 10
373 ## N-I dash stdout-json: ""
374 ## N-I dash status: 2
375
376 #### Octal constant
377 echo $(( 011 ))
378 ## stdout: 9
379 ## N-I mksh/zsh stdout: 11
380
381 #### Dynamic octal constant
382 zero=0
383 echo $(( ${zero}11 ))
384 ## stdout: 9
385 ## N-I mksh/zsh stdout: 11
386
387 #### Dynamic hex constants
388 zero=0
389 echo $(( ${zero}xAB ))
390 ## stdout: 171
391
392 #### Dynamic var names - result of runtime parse/eval
393 foo=5
394 x=oo
395 echo $(( foo + f$x + 1 ))
396 ## stdout: 11
397
398 #### Recursive name evaluation is a result of runtime parse/eval
399 foo=5
400 bar=foo
401 spam=bar
402 eggs=spam
403 echo $((foo+1)) $((bar+1)) $((spam+1)) $((eggs+1))
404 ## stdout: 6 6 6 6
405 ## N-I dash stdout-json: ""
406 ## N-I dash status: 2
407
408 #### nounset with arithmetic
409 set -o nounset
410 x=$(( y + 5 ))
411 echo "should not get here: x=${x:-<unset>}"
412 ## stdout-json: ""
413 ## status: 1
414 ## BUG dash/mksh/zsh stdout: should not get here: x=5
415 ## BUG dash/mksh/zsh status: 0
416
417 #### 64-bit integer doesn't overflow
418
419 a=$(( 1 << 31 ))
420 echo $a
421
422 b=$(( a + a ))
423 echo $b
424
425 c=$(( b + a ))
426 echo $c
427
428 x=$(( 1 << 62 ))
429 y=$(( x - 1 ))
430 echo "max positive = $(( x + y ))"
431
432 #echo "overflow $(( x + x ))"
433
434 ## STDOUT:
435 2147483648
436 4294967296
437 6442450944
438 max positive = 9223372036854775807
439 ## END
440
441 # mksh still uses int!
442 ## BUG mksh STDOUT:
443 -2147483648
444 0
445 -2147483648
446 max positive = 2147483647
447 ## END
448
449 #### More 64-bit ops
450 case $SH in dash) exit ;; esac
451
452 #shopt -s strict_arith
453
454 # This overflows - the extra 9 puts it above 2**31
455 #echo $(( 12345678909 ))
456
457 [[ 12345678909 = $(( 1 << 30 )) ]]
458 echo eq=$?
459 [[ 12345678909 = 12345678909 ]]
460 echo eq=$?
461
462 # Try both [ and [[
463 [ 12345678909 -gt $(( 1 << 30 )) ]
464 echo greater=$?
465 [[ 12345678909 -gt $(( 1 << 30 )) ]]
466 echo greater=$?
467
468 [[ 12345678909 -ge $(( 1 << 30 )) ]]
469 echo ge=$?
470 [[ 12345678909 -ge 12345678909 ]]
471 echo ge=$?
472
473 [[ 12345678909 -le $(( 1 << 30 )) ]]
474 echo le=$?
475 [[ 12345678909 -le 12345678909 ]]
476 echo le=$?
477
478 ## STDOUT:
479 eq=1
480 eq=0
481 greater=0
482 greater=0
483 ge=0
484 ge=0
485 le=1
486 le=0
487 ## END
488 ## N-I dash STDOUT:
489 ## END
490 ## BUG mksh STDOUT:
491 eq=1
492 eq=0
493 greater=1
494 greater=1
495 ge=1
496 ge=0
497 le=0
498 le=0
499 ## END
500
501 # mksh still uses int!
502
503 #### Invalid LValue
504 a=9
505 (( (a + 2) = 3 ))
506 echo $a
507 ## status: 2
508 ## stdout-json: ""
509 ## OK bash/mksh/zsh stdout: 9
510 ## OK bash/mksh/zsh status: 0
511 # dash doesn't implement assignment
512 ## N-I dash status: 2
513 ## N-I dash stdout-json: ""
514
515 #### Invalid LValue that looks like array
516 (( 1[2] = 3 ))
517 echo "status=$?"
518 ## status: 1
519 ## stdout-json: ""
520
521 ## OK bash stdout: status=1
522 ## OK bash status: 0
523
524 ## OK mksh/zsh stdout: status=2
525 ## OK mksh/zsh status: 0
526
527 ## N-I dash stdout: status=127
528 ## N-I dash status: 0
529
530 #### Invalid LValue: two sets of brackets
531 (( a[1][2] = 3 ))
532 echo "status=$?"
533 # shells treat this as a NON-fatal error
534 ## status: 2
535 ## stdout-json: ""
536 ## OK bash stdout: status=1
537 ## OK mksh/zsh stdout: status=2
538 ## OK bash/mksh/zsh status: 0
539 # dash doesn't implement assignment
540 ## N-I dash stdout: status=127
541 ## N-I dash status: 0
542
543 #### Operator Precedence
544 echo $(( 1 + 2*3 - 8/2 ))
545 ## stdout: 3
546
547 #### Exponentiation with **
548 echo $(( 3 ** 0 ))
549 echo $(( 3 ** 1 ))
550 echo $(( 3 ** 2 ))
551 ## STDOUT:
552 1
553 3
554 9
555 ## END
556 ## N-I dash stdout-json: ""
557 ## N-I dash status: 2
558 ## N-I mksh stdout-json: ""
559 ## N-I mksh status: 1
560
561 #### Exponentiation operator has buggy precedence
562 # NOTE: All shells agree on this, but R and Python give -9, which is more
563 # mathematically correct.
564 echo $(( -3 ** 2 ))
565 ## stdout: 9
566 ## N-I dash stdout-json: ""
567 ## N-I dash status: 2
568 ## N-I mksh stdout-json: ""
569 ## N-I mksh status: 1
570
571 #### Negative exponent
572 # bash explicitly disallows negative exponents!
573 echo $(( 2**-1 * 5 ))
574 ## stdout-json: ""
575 ## status: 1
576 ## OK zsh stdout: 2.5
577 ## OK zsh status: 0
578 ## N-I dash stdout-json: ""
579 ## N-I dash status: 2
580
581 #### Comment not allowed in the middle of multiline arithmetic
582 echo $((
583 1 +
584 2 + \
585 3
586 ))
587 echo $((
588 1 + 2 # not a comment
589 ))
590 (( a = 3 + 4 # comment
591 ))
592 echo [$a]
593 ## status: 1
594 ## STDOUT:
595 6
596 ## END
597 ## OK dash/osh status: 2
598 ## OK bash STDOUT:
599 6
600 []
601 ## END
602 ## OK bash status: 0
603
604 #### Add integer to indexed array (a[0] decay)
605 declare -a array=(1 2 3)
606 echo $((array + 5))
607 ## status: 0
608 ## STDOUT:
609 6
610 ## END
611 ## N-I dash status: 2
612 ## N-I dash stdout-json: ""
613 ## N-I mksh/zsh status: 1
614 ## N-I mksh/zsh stdout-json: ""
615
616 #### Add integer to associative array (a[0] decay)
617 typeset -A assoc
618 assoc[0]=42
619 echo $((assoc + 5))
620 ## status: 0
621 ## stdout: 47
622 ## BUG dash status: 0
623 ## BUG dash stdout: 5
624
625 #### Double subscript
626 a=(1 2 3)
627 echo $(( a[1] ))
628 echo $(( a[1][1] ))
629 ## status: 1
630 ## OK osh status: 2
631 ## STDOUT:
632 2
633 ## END
634 ## N-I dash status: 2
635 ## N-I dash stdout-json: ""
636 ## OK zsh STDOUT:
637 1
638 ## END
639
640 #### result of ArithSub -- array[0] decay
641 a=(4 5 6)
642 echo declared
643 b=$(( a ))
644 echo $b
645
646 ## status: 0
647 ## STDOUT:
648 declared
649 4
650 ## END
651 ## N-I dash status: 2
652 ## N-I dash stdout-json: ""
653 ## N-I zsh status: 1
654 ## N-I zsh STDOUT:
655 declared
656 ## END
657
658 #### result of ArithSub -- assoc[0] decay
659 declare -A A=(['foo']=bar ['spam']=eggs)
660 echo declared
661 b=$(( A ))
662 echo $b
663
664 ## status: 0
665 ## STDOUT:
666 declared
667 0
668 ## END
669
670 ## N-I mksh status: 1
671 ## N-I mksh stdout-json: ""
672
673
674 ## N-I dash status: 2
675 ## N-I dash stdout-json: ""
676
677 #### comma operator
678 a=(4 5 6)
679
680 # zsh and osh can't evaluate the array like that
681 # which is consistent with their behavior on $(( a ))
682
683 echo $(( a, last = a[2], 42 ))
684 echo last=$last
685
686 ## status: 0
687 ## STDOUT:
688 42
689 last=6
690 ## END
691 ## N-I dash status: 2
692 ## N-I dash stdout-json: ""
693 ## N-I zsh status: 1
694 ## N-I zsh stdout-json: ""
695
696
697 #### assignment with dynamic var name
698 foo=bar
699 echo $(( x$foo = 42 ))
700 echo xbar=$xbar
701 ## STDOUT:
702 42
703 xbar=42
704 ## END
705
706 #### array assignment with dynamic array name
707 foo=bar
708 echo $(( x$foo[5] = 42 ))
709 echo 'xbar[5]='${xbar[5]}
710 ## STDOUT:
711 42
712 xbar[5]=42
713 ## END
714 ## BUG zsh STDOUT:
715 42
716 xbar[5]=
717 ## END
718 ## N-I dash status: 2
719 ## N-I dash stdout-json: ""
720
721 #### unary assignment with dynamic var name
722 foo=bar
723 xbar=42
724 echo $(( x$foo++ ))
725 echo xbar=$xbar
726 ## STDOUT:
727 42
728 xbar=43
729 ## END
730 ## BUG dash status: 2
731 ## BUG dash stdout-json: ""
732
733 #### unary array assignment with dynamic var name
734 foo=bar
735 xbar[5]=42
736 echo $(( x$foo[5]++ ))
737 echo 'xbar[5]='${xbar[5]}
738 ## STDOUT:
739 42
740 xbar[5]=43
741 ## END
742 ## BUG zsh STDOUT:
743 0
744 xbar[5]=42
745 ## END
746 ## N-I dash status: 2
747 ## N-I dash stdout-json: ""
748
749 #### Dynamic parsing of arithmetic
750 e=1+2
751 echo $(( e + 3 ))
752 [[ e -eq 3 ]] && echo true
753 [ e -eq 3 ]
754 echo status=$?
755 ## STDOUT:
756 6
757 true
758 status=2
759 ## END
760 ## BUG mksh STDOUT:
761 6
762 true
763 status=0
764 ## END
765 ## N-I dash status: 2
766 ## N-I dash stdout-json: ""
767
768 #### Dynamic parsing on empty string
769 a=''
770 echo $(( a ))
771
772 a2=' '
773 echo $(( a2 ))
774 ## STDOUT:
775 0
776 0
777 ## END
778
779 #### nested ternary (bug fix)
780 echo $((1?2?3:4:5))
781 ## STDOUT:
782 3
783 ## END
784
785 #### 1 ? a=1 : b=2 ( bug fix)
786 echo $((1 ? a=1 : 42 ))
787 echo a=$a
788
789 # this does NOT work
790 #echo $((1 ? a=1 : b=2 ))
791
792 ## STDOUT:
793 1
794 a=1
795 ## END
796 ## BUG zsh stdout-json: ""
797 ## BUG zsh status: 1
798
799 #### Invalid constant
800
801 echo $((a + x42))
802 echo status=$?
803
804 # weird asymmetry -- the above is a syntax error, but this isn't
805 $SH -c 'echo $((a + 42x))'
806 echo status=$?
807
808 # regression
809 echo $((a + 42x))
810 echo status=$?
811 ## status: 1
812 ## STDOUT:
813 0
814 status=0
815 status=1
816 ## END
817 ## OK dash status: 2
818 ## OK dash STDOUT:
819 0
820 status=0
821 status=2
822 ## END
823 ## BUG bash status: 0
824 ## BUG bash STDOUT:
825 0
826 status=0
827 status=1
828 status=1
829 ## END
830
831 #### Negative numbers with integer division /
832
833 echo $(( 10 / 3))
834 echo $((-10 / 3))
835 echo $(( 10 / -3))
836 echo $((-10 / -3))
837
838 echo ---
839
840 a=20
841 : $(( a /= 3 ))
842 echo $a
843
844 a=-20
845 : $(( a /= 3 ))
846 echo $a
847
848 a=20
849 : $(( a /= -3 ))
850 echo $a
851
852 a=-20
853 : $(( a /= -3 ))
854 echo $a
855
856 ## STDOUT:
857 3
858 -3
859 -3
860 3
861 ---
862 6
863 -6
864 -6
865 6
866 ## END
867
868 #### Negative numbers with %
869
870 echo $(( 10 % 3))
871 echo $((-10 % 3))
872 echo $(( 10 % -3))
873 echo $((-10 % -3))
874
875 ## STDOUT:
876 1
877 -1
878 1
879 -1
880 ## END
881
882 #### Negative numbers with bit shift
883
884 echo $(( 5 << 1 ))
885 echo $(( 5 << 0 ))
886 $SH -c 'echo $(( 5 << -1 ))' # implementation defined - OSH fails
887 echo ---
888
889 echo $(( 16 >> 1 ))
890 echo $(( 16 >> 0 ))
891 $SH -c 'echo $(( 16 >> -1 ))' # not sure why this is zero
892 $SH -c 'echo $(( 16 >> -2 ))' # also 0
893 echo ---
894
895 ## STDOUT:
896 10
897 5
898 ---
899 8
900 16
901 ---
902 ## END
903
904 ## OK bash/dash/zsh STDOUT:
905 10
906 5
907 -9223372036854775808
908 ---
909 8
910 16
911 0
912 0
913 ---
914 ## END
915
916 ## BUG mksh STDOUT:
917 10
918 5
919 -2147483648
920 ---
921 8
922 16
923 0
924 0
925 ---
926 ## END
927
928 #### undef[0]
929 case $SH in dash) exit ;; esac
930
931 echo ARITH $(( undef[0] ))
932 echo status=$?
933 echo
934
935 (( undef[0] ))
936 echo status=$?
937 echo
938
939 echo UNDEF ${undef[0]}
940 echo status=$?
941
942 ## STDOUT:
943 ARITH 0
944 status=0
945
946 status=1
947
948 UNDEF
949 status=0
950 ## END
951 ## N-I dash STDOUT:
952 ## END
953
954 #### undef[0] with nounset
955 case $SH in dash) exit ;; esac
956
957 set -o nounset
958 echo UNSET $(( undef[0] ))
959 echo status=$?
960
961 ## status: 1
962 ## STDOUT:
963 ## END
964
965 ## N-I dash status: 0
966
967 ## BUG mksh/zsh status: 0
968 ## BUG mksh/zsh STDOUT:
969 UNSET 0
970 status=0
971 ## END
972
973 ## N-I dash STDOUT:
974 ## END
975
976 #### s[0] with string abc
977 case $SH in dash) exit ;; esac
978
979 s='abc'
980 echo abc $(( s[0] )) $(( s[1] ))
981 echo status=$?
982 echo
983
984 (( s[0] ))
985 echo status=$?
986 echo
987
988 ## STDOUT:
989 abc 0 0
990 status=0
991
992 status=1
993
994 ## END
995 ## N-I dash STDOUT:
996 ## END
997
998 #### s[0] with string 42
999 case $SH in dash) exit ;; esac
1000
1001 s='42'
1002 echo 42 $(( s[0] )) $(( s[1] ))
1003 echo status=$?
1004
1005 ## STDOUT:
1006 42 42 0
1007 status=0
1008 ## END
1009 ## N-I dash STDOUT:
1010 ## END
1011
1012 ## BUG zsh STDOUT:
1013 42 0 4
1014 status=0
1015 ## END
1016
1017 #### s[0] with string '12 34'
1018
1019 s='12 34'
1020 echo '12 34' $(( s[0] )) $(( s[1] ))
1021 echo status=$?
1022
1023 ## status: 1
1024 ## STDOUT:
1025 ## END
1026
1027 ## OK dash status: 2
1028
1029 ## BUG zsh status: 0
1030 ## BUG zsh STDOUT:
1031 12 34 0 1
1032 status=0
1033 ## END
1034
1035 # bash prints an error, but doesn't fail
1036
1037 ## BUG bash status: 0
1038 ## BUG bash STDOUT:
1039 status=1
1040 ## END