OILS / spec / ble-idioms.test.sh View on Github | oils.pub

623 lines, 336 significant
1## compare_shells: bash zsh mksh ash
2## oils_failures_allowed: 2
3
4#### recursive arith: one level
5a='b=123'
6echo $((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
13a='b=c' c='d=123'
14echo $((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.
25a=b=123
26echo $((1||a)):$((b))
27echo $((0||a)):$((b))
28c=d=321
29echo $((0&&c)):$((d))
30echo $((1&&c)):$((d))
31## STDOUT:
321:0
331:123
340:0
351:321
36## END
37
38## BUG mksh/ash STDOUT:
391:123
401:123
410:321
421:321
43## END
44
45## N-I dash/yash status: 2
46## N-I dash/yash STDOUT:
471:0
48## END
49
50#### recursive arith: short circuit ?:
51# Note: "busybox sh" behaves strangely.
52y=a=123 n=a=321
53echo $((1?(y):(n))):$((a))
54echo $((0?(y):(n))):$((a))
55## STDOUT:
56123:123
57321:321
58## END
59## BUG ash STDOUT:
60123:321
61321:321
62## END
63## N-I dash status: 2
64## N-I dash stdout-json: ""
65## N-I yash STDOUT:
66a=123:0
67a=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.
73a='b=c' c='d=123'
74echo $((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
81loop='i<=100&&(s+=i,i++,loop)' s=0 i=0
82echo $((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
90text[1]='d=123'
91text[2]='text[1]'
92text[3]='text[2]'
93echo $((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
99vec2_set () {
100 local this=$1 x=$2 y=$3
101 : $(( ${this}_x = $2 ))
102 : $(( ${this}_y = y ))
103}
104vec2_set a 3 4
105vec2_set b 5 12
106echo a_x=$a_x a_y=$a_y
107echo b_x=$b_x b_y=$b_y
108## STDOUT:
109a_x=3 a_y=4
110b_x=5 b_y=12
111## END
112
113#### dynamic arith varname: read
114
115vec2_load() {
116 local this=$1
117 x=$(( ${this}_x ))
118 : $(( y = ${this}_y ))
119}
120a_x=12 a_y=34
121vec2_load a
122echo x=$x y=$y
123## STDOUT:
124x=12 y=34
125## END
126
127#### dynamic arith varname: copy/add
128shopt -s eval_unsafe_arith # for RHS
129
130vec2_copy () {
131 local this=$1 rhs=$2
132 : $(( ${this}_x = $(( ${rhs}_x )) ))
133 : $(( ${this}_y = ${rhs}_y ))
134}
135vec2_add () {
136 local this=$1 rhs=$2
137 : $(( ${this}_x += $(( ${rhs}_x )) ))
138 : $(( ${this}_y += ${rhs}_y ))
139}
140a_x=3 a_y=4
141b_x=4 b_y=20
142vec2_copy c a
143echo c_x=$c_x c_y=$c_y
144vec2_add c b
145echo c_x=$c_x c_y=$c_y
146## STDOUT:
147c_x=3 c_y=4
148c_x=7 c_y=24
149## END
150
151#### is-array with ${var@a}
152case $SH in (mksh|ash|dash|yash) exit 1 ;; esac
153
154function ble/is-array { [[ ${!1@a} == *a* ]]; }
155
156ble/is-array undef
157echo undef $?
158
159string=''
160ble/is-array string
161echo string $?
162
163array=(one two three)
164ble/is-array array
165echo array $?
166## STDOUT:
167undef 1
168string 1
169array 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
179a=()
180
181if false; then
182 # This takes too long! # From Zulip
183 i=$(( 0x0100000000000000 ))
184else
185 # smaller number that's OK
186 i=$(( 0x0100000 ))
187fi
188
189a[i]=1
190
191echo len=${#a[@]}
192
193## STDOUT:
194len=1
195## END
196
197## N-I ash status: 2
198## N-I ash STDOUT:
199## END
200
201## BUG zsh STDOUT:
202len=1048576
203## END
204
205
206#### shift unshift reverse
207
208case $SH in mksh|ash) exit ;; esac
209
210# https://github.com/akinomyoga/ble.sh/blob/79beebd928cf9f6506a687d395fd450d027dc4cd/src/util.sh#L578-L582
211
212# @fn ble/array#unshift arr value...
213function ble/array#unshift {
214 builtin eval -- "$1=(\"\${@:2}\" \"\${$1[@]}\")"
215}
216# @fn ble/array#shift arr count
217function ble/array#shift {
218 # Note: Bash 4.3 以下では ${arr[@]:${2:-1}} が offset='${2'
219 # length='-1' に解釈されるので、先に算術式展開させる。
220 builtin eval -- "$1=(\"\${$1[@]:$((${2:-1}))}\")"
221}
222# @fn ble/array#reverse arr
223function ble/array#reverse {
224 builtin eval "
225 set -- \"\${$1[@]}\"; $1=()
226 local e$1 i$1=\$#
227 for e$1; do $1[--i$1]=\"\$e$1\"; done"
228}
229
230a=( {1..6} )
231echo "${a[@]}"
232
233ble/array#shift a 1
234echo "${a[@]}"
235
236ble/array#shift a 2
237echo "${a[@]}"
238
239echo ---
240
241ble/array#unshift a 99
242echo "${a[@]}"
243
244echo ---
245
246# doesn't work in zsh!
247ble/array#reverse a
248echo "${a[@]}"
249
250
251## STDOUT:
2521 2 3 4 5 6
2532 3 4 5 6
2544 5 6
255---
25699 4 5 6
257---
2586 5 4 99
259## END
260
261## BUG zsh STDOUT:
2621 2 3 4 5 6
2632 3 4 5 6
2644 5 6
265---
26699 4 5 6
267---
2685 4 99
269## END
270
271## N-I mksh/ash STDOUT:
272## END
273
274
275#### shopt -u expand_aliases and eval
276case $SH in zsh|mksh|ash) exit ;; esac
277
278alias echo=false
279
280function f {
281 shopt -u expand_aliases
282 eval -- "$1"
283 shopt -s expand_aliases
284}
285
286f 'echo hello'
287
288## STDOUT:
289hello
290## END
291## N-I zsh/mksh/ash STDOUT:
292## END
293
294
295#### Tilde expansions in RHS of designated array initialization
296case $SH in zsh|mksh|ash) exit ;; esac
297
298HOME=/home/user
299declare -A a
300declare -A a=(['home']=~ ['hello']=~:~:~)
301echo "${a['home']}"
302echo "${a['hello']}"
303
304## STDOUT:
305/home/user
306/home/user:/home/user:/home/user
307## END
308
309# Note: bash-5.2 has a bug that the tilde doesn't expand on the right hand side
310# of [key]=value. This problem doesn't happen in bash-3.1..5.1 and bash-5.3.
311## BUG bash STDOUT:
312~
313~:~:~
314## END
315
316## N-I zsh/mksh/ash stdout-json: ""
317
318
319#### InitializerList (BashArray): index increments with
320case $SH in zsh|mksh|ash) exit 99;; esac
321a=([100]=1 2 3 4)
322printf 'keys: '; argv.py "${!a[@]}"
323printf 'vals: '; argv.py "${a[@]}"
324a=([100]=1 2 3 4 [5]=a b c d)
325printf 'keys: '; argv.py "${!a[@]}"
326printf 'vals: '; argv.py "${a[@]}"
327## STDOUT:
328keys: ['100', '101', '102', '103']
329vals: ['1', '2', '3', '4']
330keys: ['5', '6', '7', '8', '100', '101', '102', '103']
331vals: ['a', 'b', 'c', 'd', '1', '2', '3', '4']
332## END
333## N-I zsh/mksh/ash status: 99
334## N-I zsh/mksh/ash stdout-json: ""
335
336#### InitializerList (BashArray): [k]=$v and [k]="$@"
337case $SH in zsh|mksh|ash) exit 99;; esac
338i=5
339v='1 2 3'
340a=($v [i]=$v)
341printf 'keys: '; argv.py "${!a[@]}"
342printf 'vals: '; argv.py "${a[@]}"
343
344x=(3 5 7)
345a=($v [i]="${x[*]}")
346printf 'keys: '; argv.py "${!a[@]}"
347printf 'vals: '; argv.py "${a[@]}"
348a=($v [i]="${x[@]}")
349printf 'keys: '; argv.py "${!a[@]}"
350printf 'vals: '; argv.py "${a[@]}"
351a=($v [i]=${x[*]})
352printf 'keys: '; argv.py "${!a[@]}"
353printf 'vals: '; argv.py "${a[@]}"
354a=($v [i]=${x[@]})
355printf 'keys: '; argv.py "${!a[@]}"
356printf 'vals: '; argv.py "${a[@]}"
357## STDOUT:
358keys: ['0', '1', '2', '5']
359vals: ['1', '2', '3', '1 2 3']
360keys: ['0', '1', '2', '5']
361vals: ['1', '2', '3', '3 5 7']
362keys: ['0', '1', '2', '5']
363vals: ['1', '2', '3', '3 5 7']
364keys: ['0', '1', '2', '5']
365vals: ['1', '2', '3', '3 5 7']
366keys: ['0', '1', '2', '5']
367vals: ['1', '2', '3', '3 5 7']
368## END
369## N-I zsh/mksh/ash status: 99
370## N-I zsh/mksh/ash stdout-json: ""
371
372
373#### InitializerList (BashAssoc): [k]=$v and [k]="$@"
374case $SH in zsh|mksh|ash) exit 99;; esac
375i=5
376v='1 2 3'
377declare -A a
378a=([i]=$v)
379printf 'keys: '; argv.py "${!a[@]}"
380printf 'vals: '; argv.py "${a[@]}"
381
382x=(3 5 7)
383a=([i]="${x[*]}")
384printf 'keys: '; argv.py "${!a[@]}"
385printf 'vals: '; argv.py "${a[@]}"
386a=([i]="${x[@]}")
387printf 'keys: '; argv.py "${!a[@]}"
388printf 'vals: '; argv.py "${a[@]}"
389a=([i]=${x[*]})
390printf 'keys: '; argv.py "${!a[@]}"
391printf 'vals: '; argv.py "${a[@]}"
392a=([i]=${x[@]})
393printf 'keys: '; argv.py "${!a[@]}"
394printf 'vals: '; argv.py "${a[@]}"
395## STDOUT:
396keys: ['i']
397vals: ['1 2 3']
398keys: ['i']
399vals: ['3 5 7']
400keys: ['i']
401vals: ['3 5 7']
402keys: ['i']
403vals: ['3 5 7']
404keys: ['i']
405vals: ['3 5 7']
406## END
407## N-I zsh/mksh/ash status: 99
408## N-I zsh/mksh/ash stdout-json: ""
409
410#### InitializerList (BashArray): append to element
411case $SH in zsh|mksh|ash) exit 99;; esac
412hello=100
413a=([hello]=1 [hello]+=2)
414printf 'keys: '; argv.py "${!a[@]}"
415printf 'vals: '; argv.py "${a[@]}"
416a+=([hello]+=:34 [hello]+=:56)
417printf 'keys: '; argv.py "${!a[@]}"
418printf 'vals: '; argv.py "${a[@]}"
419## STDOUT:
420keys: ['100']
421vals: ['12']
422keys: ['100']
423vals: ['12:34:56']
424## END
425## N-I zsh/mksh/ash status: 99
426## N-I zsh/mksh/ash stdout-json: ""
427
428#### InitializerList (BashAssoc): append to element
429case $SH in zsh|mksh|ash) exit 99;; esac
430declare -A a
431hello=100
432a=([hello]=1 [hello]+=2)
433printf 'keys: '; argv.py "${!a[@]}"
434printf 'vals: '; argv.py "${a[@]}"
435a+=([hello]+=:34 [hello]+=:56)
436printf 'keys: '; argv.py "${!a[@]}"
437printf 'vals: '; argv.py "${a[@]}"
438## STDOUT:
439keys: ['hello']
440vals: ['12']
441keys: ['hello']
442vals: ['12:34:56']
443## END
444# Bash >= 5.1 has a bug. Bash <= 5.0 is OK.
445## BUG bash STDOUT:
446keys: ['hello']
447vals: ['2']
448keys: ['hello']
449vals: ['2:34:56']
450## END
451## N-I zsh/mksh/ash status: 99
452## N-I zsh/mksh/ash stdout-json: ""
453
454#### InitializerList (BashAssoc): non-index forms of element
455case $SH in zsh|mksh|ash) exit 99;; esac
456declare -A a
457a=([j]=1 2 3 4)
458echo "status=$?"
459printf 'keys: '; argv.py "${!a[@]}"
460printf 'vals: '; argv.py "${a[@]}"
461## status: 1
462## STDOUT:
463## END
464# Bash outputs warning messages and succeeds (exit status 0)
465## BUG bash status: 0
466## BUG bash STDOUT:
467status=0
468keys: ['j']
469vals: ['1']
470## END
471## BUG bash STDERR:
472bash: line 3: a: 2: must use subscript when assigning associative array
473bash: line 3: a: 3: must use subscript when assigning associative array
474bash: line 3: a: 4: must use subscript when assigning associative array
475## END
476## N-I zsh/mksh/ash status: 99
477## N-I zsh/mksh/ash stdout-json: ""
478
479
480#### InitializerList (BashArray): evaluation order (1)
481# RHS of [k]=v are expanded when the initializer list is instanciated. For the
482# indexed array, the array indices are evaluated when the array is modified.
483case $SH in zsh|mksh|ash) exit 99;; esac
484i=1
485a=([100+i++]=$((i++)) [200+i++]=$((i++)) [300+i++]=$((i++)))
486printf 'keys: '; argv.py "${!a[@]}"
487printf 'vals: '; argv.py "${a[@]}"
488## STDOUT:
489keys: ['104', '205', '306']
490vals: ['1', '2', '3']
491## END
492## N-I zsh/mksh/ash status: 99
493## N-I zsh/mksh/ash stdout-json: ""
494
495
496#### InitializerList (BashArray): evaluation order (2)
497# When evaluating the index, the modification to the array by the previous item
498# of the initializer list is visible to the current item.
499case $SH in zsh|mksh|ash) exit 99;; esac
500a=([0]=1+2+3 [a[0]]=10 [a[6]]=hello)
501printf 'keys: '; argv.py "${!a[@]}"
502printf 'vals: '; argv.py "${a[@]}"
503## STDOUT:
504keys: ['0', '6', '10']
505vals: ['1+2+3', '10', 'hello']
506## END
507## N-I zsh/mksh/ash status: 99
508## N-I zsh/mksh/ash stdout-json: ""
509
510
511#### InitializerList (BashArray): evaluation order (3)
512# RHS should be expanded before any modification to the array.
513case $SH in zsh|mksh|ash) exit 99;; esac
514a=(old1 old2 old3)
515a=("${a[2]}" "${a[0]}" "${a[1]}" "${a[2]}" "${a[0]}")
516printf 'keys: '; argv.py "${!a[@]}"
517printf 'vals: '; argv.py "${a[@]}"
518a=(old1 old2 old3)
519old1=101 old2=102 old3=103
520new1=201 new2=202 new3=203
521a+=([0]=new1 [1]=new2 [2]=new3 [5]="${a[2]}" [a[0]]="${a[0]}" [a[1]]="${a[1]}")
522printf 'keys: '; argv.py "${!a[@]}"
523printf 'vals: '; argv.py "${a[@]}"
524## STDOUT:
525keys: ['0', '1', '2', '3', '4']
526vals: ['old3', 'old1', 'old2', 'old3', 'old1']
527keys: ['0', '1', '2', '5', '201', '202']
528vals: ['new1', 'new2', 'new3', 'old3', 'old1', 'old2']
529## END
530## N-I zsh/mksh/ash status: 99
531## N-I zsh/mksh/ash stdout-json: ""
532
533
534#### Issue #1069 [57] - Variable v should be visible after IFS= eval 'local v=...'
535
536set -u
537
538f() {
539 # The temp env messes it up
540 IFS= eval "local v=\"\$*\""
541
542 # Bug does not appear with only eval
543 # eval "local v=\"\$*\""
544
545 #declare -p v
546 echo v=$v
547
548 # test -v v; echo "v defined $?"
549}
550
551f h e l l o
552
553## STDOUT:
554v=hello
555## END
556
557
558#### Issue #1069 [59] - Assigning Str to BashArray/BashAssoc should not remove BashArray/BashAssoc
559case $SH in zsh|ash) exit ;; esac
560
561a=(1 2 3)
562a=99
563typeset -p a
564
565typeset -A A=([k]=v)
566A=99
567typeset -p A
568
569## STDOUT:
570declare -a a=([0]="99" [1]="2" [2]="3")
571declare -A A=([0]="99" [k]="v" )
572## END
573
574## OK mksh status: 1
575## OK mksh STDOUT:
576set -A a
577typeset a[0]=99
578typeset a[1]=2
579typeset a[2]=3
580## END
581
582## N-I zsh/ash STDOUT:
583## END
584
585#### Issue #1069 [53] - LHS array parsing a[1 + 2]=3 (see spec/array-assign for more)
586case $SH in zsh|ash) exit ;; esac
587
588a[1 + 2]=7
589a[3|4]=8
590a[(1+2)*3]=9
591
592typeset -p a
593
594# Dynamic parsing
595expr='1 + 2'
596a[expr]=55
597
598b=(42)
599expr='b[0]'
600a[3 + $expr - 4]=66
601
602typeset -p a
603
604## STDOUT:
605declare -a a=([3]="7" [7]="8" [9]="9")
606declare -a a=([3]="55" [7]="8" [9]="9" [41]="66")
607## END
608
609## OK mksh STDOUT:
610set -A a
611typeset a[3]=7
612typeset a[7]=8
613typeset a[9]=9
614set -A a
615typeset a[3]=55
616typeset a[7]=8
617typeset a[9]=9
618typeset a[41]=66
619## END
620
621## N-I zsh/ash STDOUT:
622## END
623