1 ## compare_shells: bash zsh mksh ash
2 ## oils_failures_allowed: 5
3
4 #### recursive arith: one level
5 a='b=123'
6 echo $((a))
7 ## stdout: 123
8 ## N-I dash status: 2
9 ## N-I dash stdout-json: ""
10 ## N-I yash stdout: b=123
11
12 #### recursive arith: two levels
13 a='b=c' c='d=123'
14 echo $((a))
15 ## stdout: 123
16 ## N-I dash status: 2
17 ## N-I dash stdout-json: ""
18 ## N-I yash stdout: b=c
19
20 #### recursive arith: short circuit &&, ||
21 # Note: mksh R52 has a bug. Even though it supports a short circuit like
22 # "echo $((cond&&(a=1)))", it doesn't work with "x=a=1; echo
23 # $((cond&&x))". It is fixed at least in mksh R57.
24 # Note: "busybox sh" doesn't support short circuit.
25 a=b=123
26 echo $((1||a)):$((b))
27 echo $((0||a)):$((b))
28 c=d=321
29 echo $((0&&c)):$((d))
30 echo $((1&&c)):$((d))
31 ## STDOUT:
32 1:0
33 1:123
34 0:0
35 1:321
36 ## END
37
38 ## BUG mksh/ash STDOUT:
39 1:123
40 1:123
41 0:321
42 1:321
43 ## END
44
45 ## N-I dash/yash status: 2
46 ## N-I dash/yash STDOUT:
47 1:0
48 ## END
49
50 #### recursive arith: short circuit ?:
51 # Note: "busybox sh" behaves strangely.
52 y=a=123 n=a=321
53 echo $((1?(y):(n))):$((a))
54 echo $((0?(y):(n))):$((a))
55 ## STDOUT:
56 123:123
57 321:321
58 ## END
59 ## BUG ash STDOUT:
60 123:321
61 321:321
62 ## END
63 ## N-I dash status: 2
64 ## N-I dash stdout-json: ""
65 ## N-I yash STDOUT:
66 a=123:0
67 a=321:0
68 ## END
69
70 #### recursive arith: side effects
71 # In Zsh and Busybox sh, the side effect of inner arithmetic
72 # evaluations seems to take effect only after the whole evaluation.
73 a='b=c' c='d=123'
74 echo $((a,d)):$((d))
75 ## stdout: 123:123
76 ## BUG zsh/ash stdout: 0:123
77 ## N-I dash/yash status: 2
78 ## N-I dash/yash stdout-json: ""
79
80 #### recursive arith: recursion
81 loop='i<=100&&(s+=i,i++,loop)' s=0 i=0
82 echo $((a=loop,s))
83 ## stdout: 5050
84 ## N-I mksh status: 1
85 ## N-I mksh stdout-json: ""
86 ## N-I ash/dash/yash status: 2
87 ## N-I ash/dash/yash stdout-json: ""
88
89 #### recursive arith: array elements
90 text[1]='d=123'
91 text[2]='text[1]'
92 text[3]='text[2]'
93 echo $((a=text[3]))
94 ## stdout: 123
95 ## N-I ash/dash/yash status: 2
96 ## N-I ash/dash/yash stdout-json: ""
97
98 #### dynamic arith varname: assign
99 vec2_set () {
100 local this=$1 x=$2 y=$3
101 : $(( ${this}_x = $2 ))
102 : $(( ${this}_y = y ))
103 }
104 vec2_set a 3 4
105 vec2_set b 5 12
106 echo a_x=$a_x a_y=$a_y
107 echo b_x=$b_x b_y=$b_y
108 ## STDOUT:
109 a_x=3 a_y=4
110 b_x=5 b_y=12
111 ## END
112
113 #### dynamic arith varname: read
114
115 vec2_load() {
116 local this=$1
117 x=$(( ${this}_x ))
118 : $(( y = ${this}_y ))
119 }
120 a_x=12 a_y=34
121 vec2_load a
122 echo x=$x y=$y
123 ## STDOUT:
124 x=12 y=34
125 ## END
126
127 #### dynamic arith varname: copy/add
128 shopt -s eval_unsafe_arith # for RHS
129
130 vec2_copy () {
131 local this=$1 rhs=$2
132 : $(( ${this}_x = $(( ${rhs}_x )) ))
133 : $(( ${this}_y = ${rhs}_y ))
134 }
135 vec2_add () {
136 local this=$1 rhs=$2
137 : $(( ${this}_x += $(( ${rhs}_x )) ))
138 : $(( ${this}_y += ${rhs}_y ))
139 }
140 a_x=3 a_y=4
141 b_x=4 b_y=20
142 vec2_copy c a
143 echo c_x=$c_x c_y=$c_y
144 vec2_add c b
145 echo c_x=$c_x c_y=$c_y
146 ## STDOUT:
147 c_x=3 c_y=4
148 c_x=7 c_y=24
149 ## END
150
151 #### is-array with ${var@a}
152 case $SH in mksh|ash|dash|yash) exit 1 ;; esac
153
154 function ble/is-array { [[ ${!1@a} == *a* ]]; }
155
156 ble/is-array undef
157 echo undef $?
158
159 string=''
160 ble/is-array string
161 echo string $?
162
163 array=(one two three)
164 ble/is-array array
165 echo array $?
166 ## STDOUT:
167 undef 1
168 string 1
169 array 0
170 ## END
171 ## N-I zsh/mksh/ash/dash/yash status: 1
172 ## N-I zsh/mksh/ash/dash/yash stdout-json: ""
173
174
175 #### Sparse array with big index
176
177 # TODO: more InternalStringArray idioms / stress tests ?
178
179 a=()
180
181 if false; then
182 # This takes too long! # From Zulip
183 i=$(( 0x0100000000000000 ))
184 else
185 # smaller number that's OK
186 i=$(( 0x0100000 ))
187 fi
188
189 a[i]=1
190
191 echo len=${#a[@]}
192
193 ## STDOUT:
194 len=1
195 ## END
196
197 ## N-I ash/dash status: 2
198 ## N-I ash/dash STDOUT:
199 ## END
200 ## N-I yash STDOUT:
201 len=
202 ## END
203
204 ## BUG zsh STDOUT:
205 len=1048576
206 ## END
207
208
209 #### shift unshift reverse
210
211 case $SH in mksh|ash) exit ;; esac
212
213 # https://github.com/akinomyoga/ble.sh/blob/79beebd928cf9f6506a687d395fd450d027dc4cd/src/util.sh#L578-L582
214
215 # @fn ble/array#unshift arr value...
216 function ble/array#unshift {
217 builtin eval -- "$1=(\"\${@:2}\" \"\${$1[@]}\")"
218 }
219 # @fn ble/array#shift arr count
220 function ble/array#shift {
221 # Note: Bash 4.3 以下では ${arr[@]:${2:-1}} が offset='${2'
222 # length='-1' に解釈されるので、先に算術式展開させる。
223 builtin eval -- "$1=(\"\${$1[@]:$((${2:-1}))}\")"
224 }
225 # @fn ble/array#reverse arr
226 function ble/array#reverse {
227 builtin eval "
228 set -- \"\${$1[@]}\"; $1=()
229 local e$1 i$1=\$#
230 for e$1; do $1[--i$1]=\"\$e$1\"; done"
231 }
232
233 a=( {1..6} )
234 echo "${a[@]}"
235
236 ble/array#shift a 1
237 echo "${a[@]}"
238
239 ble/array#shift a 2
240 echo "${a[@]}"
241
242 echo ---
243
244 ble/array#unshift a 99
245 echo "${a[@]}"
246
247 echo ---
248
249 # doesn't work in zsh!
250 ble/array#reverse a
251 echo "${a[@]}"
252
253
254 ## STDOUT:
255 1 2 3 4 5 6
256 2 3 4 5 6
257 4 5 6
258 ---
259 99 4 5 6
260 ---
261 6 5 4 99
262 ## END
263
264 ## BUG zsh STDOUT:
265 1 2 3 4 5 6
266 2 3 4 5 6
267 4 5 6
268 ---
269 99 4 5 6
270 ---
271 5 4 99
272 ## END
273
274 ## N-I dash status: 2
275 ## N-I mksh/ash/dash STDOUT:
276 ## END
277 # Note: yash does not support calling function name with '#'
278 ## N-I yash STDOUT:
279 {1..6}
280 {1..6}
281 {1..6}
282 ---
283 {1..6}
284 ---
285 {1..6}
286 ## END
287
288
289 #### shopt -u expand_aliases and eval
290 case $SH in zsh|mksh|ash|dash|yash) exit ;; esac
291
292 alias echo=false
293
294 function f {
295 shopt -u expand_aliases
296 eval -- "$1"
297 shopt -s expand_aliases
298 }
299
300 f 'echo hello'
301
302 ## STDOUT:
303 hello
304 ## END
305 ## N-I zsh/mksh/ash/dash/yash STDOUT:
306 ## END
307
308
309 #### Issue #1069 [40] BUG: a=(declare v); "${a[@]}" fails
310 case $SH in ash|dash) exit 99 ;; esac
311 a=(typeset v=1)
312 v=x
313 "${a[@]}"
314 echo "v=$v"
315 ## STDOUT:
316 v=1
317 ## END
318 # Note: ash/dash does not have arrays
319 ## N-I ash/dash status: 99
320 ## N-I ash/dash stdout-json: ""
321
322
323 #### Issue #1069 [40] BUG: a=declare; "$a" v=1 fails
324 case $SH in ash|dash) exit 99 ;; esac
325 a=typeset
326 v=x
327 "$a" v=1
328 echo "v=$v"
329 ## STDOUT:
330 v=1
331 ## END
332 ## N-I ash/dash status: 99
333 ## N-I ash/dash stdout-json: ""
334
335
336 #### Issue #1069 [49] BUG: \return 0 does not work
337 f0() { return 3; echo unexpected; return 0; }
338 f1() { \return 3; echo unexpected; return 0; }
339 f0; echo "status=$?"
340 f1; echo "status=$?"
341 ## STDOUT:
342 status=3
343 status=3
344 ## END
345
346
347 #### Issue #1069 [49] BUG: \return 0 does not work (other variations)
348 f2() { builtin return 3; echo unexpected; return 0; }
349 f3() { \builtin return 3; echo unexpected; return 0; }
350 f4() { command return 3; echo unexpected; return 0; }
351 f2; echo "status=$?"
352 f3; echo "status=$?"
353 f4; echo "status=$?"
354 ## STDOUT:
355 status=3
356 status=3
357 status=3
358 ## END
359 # Note: zsh does not allow calling builtin through command
360 ## OK zsh STDOUT:
361 status=3
362 status=3
363 unexpected
364 status=0
365 ## END
366 # Note: ash does not have "builtin"
367 ## N-I ash/dash/yash STDOUT:
368 unexpected
369 status=0
370 unexpected
371 status=0
372 status=3
373 ## END
374
375
376 #### Issue #1069 [52] BUG: \builtin local v=1 fails
377 case $SH in ash|dash|yash) exit 99 ;; esac
378 v=x
379 case $SH in
380 mksh) f1() { \builtin typeset v=1; echo "l:v=$v"; } ;;
381 *) f1() { \builtin local v=1; echo "l:v=$v"; } ;;
382 esac
383 f1
384 echo "g:v=$v"
385 ## STDOUT:
386 l:v=1
387 g:v=x
388 ## END
389 # Note: ash/dash/yash does not have "builtin"
390 ## N-I ash/dash/yash status: 99
391 ## N-I ash/dash/yash stdout-json: ""
392
393
394 #### Issue #1069 [53] BUG: a[1 + 1]=2, etc. fails
395 case $SH in ash|dash|yash) exit 99 ;; esac
396 a=()
397
398 a[1]=x
399 eval 'a[5&3]=hello'
400 echo "status=$?, a[1]=${a[1]}"
401
402 a[2]=x
403 eval 'a[1 + 1]=hello'
404 echo "status=$?, a[2]=${a[2]}"
405
406 a[3]=x
407 eval 'a[1|2]=hello'
408 echo "status=$?, a[3]=${a[3]}"
409 ## STDOUT:
410 status=0, a[1]=hello
411 status=0, a[2]=hello
412 status=0, a[3]=hello
413 ## END
414 ## OK zsh STDOUT:
415 status=1, a[1]=x
416 status=1, a[2]=x
417 status=1, a[3]=x
418 ## END
419 # Note: ash/dash does not have arrays
420 # Note: yash does not support a[index]=value
421 ## N-I ash/dash/yash status: 99
422 ## N-I ash/dash/yash stdout-json: ""
423
424
425 #### Issue #1069 [53] - LHS array parsing a[1 + 2]=3 (see spec/array-assign for more)
426 case $SH in zsh|ash) exit ;; esac
427
428 a[1 + 2]=7
429 a[3|4]=8
430 a[(1+2)*3]=9
431
432 typeset -p a
433
434 # Dynamic parsing
435 expr='1 + 2'
436 a[expr]=55
437
438 b=(42)
439 expr='b[0]'
440 a[3 + $expr - 4]=66
441
442 typeset -p a
443
444 ## STDOUT:
445 declare -a a=([3]="7" [7]="8" [9]="9")
446 declare -a a=([3]="55" [7]="8" [9]="9" [41]="66")
447 ## END
448
449 ## OK mksh STDOUT:
450 set -A a
451 typeset a[3]=7
452 typeset a[7]=8
453 typeset a[9]=9
454 set -A a
455 typeset a[3]=55
456 typeset a[7]=8
457 typeset a[9]=9
458 typeset a[41]=66
459 ## END
460
461 ## N-I zsh/ash STDOUT:
462 ## END
463
464
465 #### Issue #1069 [56] BUG: declare -p unset does not print any error message
466 typeset -p nonexistent
467 ## status: 1
468 ## STDERR:
469 [ stdin ]:1: osh: typeset: 'nonexistent' is not defined
470 ## END
471 ## STDOUT:
472 ## END
473 ## OK bash STDERR:
474 bash: line 1: typeset: nonexistent: not found
475 ## END
476 ## OK mksh status: 0
477 ## OK mksh STDERR:
478 ## END
479 ## OK zsh STDERR:
480 typeset: no such variable: nonexistent
481 ## END
482 ## OK ash status: 127
483 ## OK ash STDERR:
484 ash: typeset: not found
485 ## END
486 ## OK dash status: 127
487 ## OK dash STDERR:
488 dash: 1: typeset: not found
489 ## END
490 ## OK yash STDERR:
491 typeset: no such variable $nonexistent
492 ## END
493
494
495 #### Issue #1069 [57] BUG: variable v is invisible after IFS= eval 'local v=...'
496 v=x
497 case $SH in
498 mksh) f() { IFS= eval 'typeset v=1'; echo "l:$v"; } ;;
499 *) f() { IFS= eval 'local v=1'; echo "l:$v"; } ;;
500 esac
501 f
502 echo "g:$v"
503 ## STDOUT:
504 l:1
505 g:x
506 ## END
507
508
509 #### Issue #1069 [57] - Variable v should be visible after IFS= eval 'local v=...'
510
511 set -u
512
513 f() {
514 # The temp env messes it up
515 IFS= eval "local v=\"\$*\""
516
517 # Bug does not appear with only eval
518 # eval "local v=\"\$*\""
519
520 #declare -p v
521 echo v=$v
522
523 # test -v v; echo "v defined $?"
524 }
525
526 f h e l l o
527
528 ## STDOUT:
529 v=hello
530 ## END
531
532
533 #### Issue #1069 [59] N-I: arr=s should set RHS to arr[0]
534 case $SH in ash|dash) exit 99 ;; esac
535 a=(1 2 3)
536 a=v
537 argv.py "${a[@]}"
538 ## STDOUT:
539 ['v', '2', '3']
540 ## END
541 ## N-I zsh/yash STDOUT:
542 ['v']
543 ## END
544 # Note: ash/dash does not have arrays
545 ## N-I ash/dash status: 99
546 ## N-I ash/dash stdout-json: ""
547
548
549 #### Issue #1069 [59] - Assigning Str to BashArray/BashAssoc should not remove BashArray/BashAssoc
550 case $SH in zsh|ash) exit ;; esac
551
552 a=(1 2 3)
553 a=99
554 typeset -p a
555
556 typeset -A A=([k]=v)
557 A=99
558 typeset -p A
559
560 ## STDOUT:
561 declare -a a=([0]="99" [1]="2" [2]="3")
562 declare -A A=([0]="99" [k]="v" )
563 ## END
564
565 ## OK mksh status: 1
566 ## OK mksh STDOUT:
567 set -A a
568 typeset a[0]=99
569 typeset a[1]=2
570 typeset a[2]=3
571 ## END
572
573 ## N-I zsh/ash STDOUT:
574 ## END