1 | ## oils_failures_allowed: 7
|
2 | ## compare_shells: bash mksh
|
3 |
|
4 | #### pass array by reference
|
5 | show_value() {
|
6 | local -n array_name=$1
|
7 | local idx=$2
|
8 | echo "${array_name[$idx]}"
|
9 | }
|
10 | shadock=(ga bu zo meu)
|
11 | show_value shadock 2
|
12 | ## stdout: zo
|
13 |
|
14 | #### mutate array by reference
|
15 | set1() {
|
16 | local -n array_name=$1
|
17 | local val=$2
|
18 | array_name[1]=$val
|
19 | }
|
20 | shadock=(a b c d)
|
21 | set1 shadock ZZZ
|
22 | echo ${shadock[@]}
|
23 | ## STDOUT:
|
24 | a ZZZ c d
|
25 | ## END
|
26 |
|
27 | #### pass assoc array by reference
|
28 | show_value() {
|
29 | local -n array_name=$1
|
30 | local idx=$2
|
31 | echo "${array_name[$idx]}"
|
32 | }
|
33 | days=([monday]=eggs [tuesday]=bread [sunday]=jam)
|
34 | show_value days sunday
|
35 | ## stdout: jam
|
36 | ## BUG mksh stdout: [monday]=eggs
|
37 | # mksh note: it coerces "days" to 0? Horrible.
|
38 |
|
39 | #### pass local array by reference, relying on DYNAMIC SCOPING
|
40 | show_value() {
|
41 | local -n array_name=$1
|
42 | local idx=$2
|
43 | echo "${array_name[$idx]}"
|
44 | }
|
45 | caller() {
|
46 | local shadock=(ga bu zo meu)
|
47 | show_value shadock 2
|
48 | }
|
49 | caller
|
50 | ## stdout: zo
|
51 | # mksh appears not to have local arrays!
|
52 | ## BUG mksh stdout-json: ""
|
53 | ## BUG mksh status: 1
|
54 |
|
55 |
|
56 | #### flag -n and +n
|
57 | x=foo
|
58 |
|
59 | ref=x
|
60 |
|
61 | echo ref=$ref
|
62 |
|
63 | typeset -n ref
|
64 | echo ref=$ref
|
65 |
|
66 | # mutate underlying var
|
67 | x=bar
|
68 | echo ref=$ref
|
69 |
|
70 | typeset +n ref
|
71 | echo ref=$ref
|
72 |
|
73 | ## STDOUT:
|
74 | ref=x
|
75 | ref=foo
|
76 | ref=bar
|
77 | ref=x
|
78 | ## END
|
79 |
|
80 | #### mutating through nameref: ref=
|
81 | x=XX
|
82 | y=YY
|
83 |
|
84 | ref=x
|
85 | ref=y
|
86 | echo 1 ref=$ref
|
87 |
|
88 | # now it's a reference
|
89 | typeset -n ref
|
90 |
|
91 | echo 2 ref=$ref # prints YY
|
92 |
|
93 | ref=XXXX
|
94 | echo 3 ref=$ref # it actually prints y, which is XXXX
|
95 |
|
96 | # now Y is mutated!
|
97 | echo 4 y=$y
|
98 |
|
99 | ## STDOUT:
|
100 | 1 ref=y
|
101 | 2 ref=YY
|
102 | 3 ref=XXXX
|
103 | 4 y=XXXX
|
104 | ## END
|
105 |
|
106 |
|
107 | #### flag -n combined ${!ref} -- bash INVERTS
|
108 | foo=FOO # should NOT use this
|
109 |
|
110 | x=foo
|
111 | ref=x
|
112 |
|
113 | echo ref=$ref
|
114 | echo "!ref=${!ref}"
|
115 |
|
116 | echo 'NOW A NAMEREF'
|
117 |
|
118 | typeset -n ref
|
119 | echo ref=$ref
|
120 | echo "!ref=${!ref}"
|
121 |
|
122 | ## STDOUT:
|
123 | ref=x
|
124 | !ref=foo
|
125 | NOW A NAMEREF
|
126 | ref=foo
|
127 | !ref=x
|
128 | ## END
|
129 | ## N-I mksh STDOUT:
|
130 | ref=x
|
131 | !ref=ref
|
132 | NOW A NAMEREF
|
133 | ref=foo
|
134 | !ref=x
|
135 | ## END
|
136 |
|
137 | #### named ref with $# doesn't work
|
138 | set -- one two three
|
139 |
|
140 | ref='#'
|
141 | echo ref=$ref
|
142 | typeset -n ref
|
143 | echo ref=$ref
|
144 |
|
145 | ## STDOUT:
|
146 | ref=#
|
147 | ref=#
|
148 | ## END
|
149 |
|
150 | # mksh does respect it!! Gah.
|
151 | ## OK mksh STDOUT:
|
152 | ref=#
|
153 | ref=3
|
154 | ## END
|
155 |
|
156 |
|
157 | #### named ref with $# and shopt -s strict_nameref
|
158 | shopt -s strict_nameref
|
159 |
|
160 | ref='#'
|
161 | echo ref=$ref
|
162 | typeset -n ref
|
163 | echo ref=$ref
|
164 | ## STDOUT:
|
165 | ref=#
|
166 | ## END
|
167 | ## status: 1
|
168 | ## N-I bash status: 0
|
169 | ## N-I bash STDOUT:
|
170 | ref=#
|
171 | ref=#
|
172 | ## END
|
173 | ## N-I mksh status: 0
|
174 | ## N-I mksh STDOUT:
|
175 | ref=#
|
176 | ref=0
|
177 | ## END
|
178 |
|
179 | #### named ref with 1 $1 etc.
|
180 | set -- one two three
|
181 |
|
182 | x=X
|
183 |
|
184 | ref='1'
|
185 | echo ref=$ref
|
186 | typeset -n ref
|
187 | echo ref=$ref
|
188 |
|
189 | # BUG: This is really assigning '1', which is INVALID
|
190 | # with strict_nameref that degrades!!!
|
191 | ref2='$1'
|
192 | echo ref2=$ref2
|
193 | typeset -n ref2
|
194 | echo ref2=$ref2
|
195 |
|
196 | x=foo
|
197 |
|
198 | ref3='x'
|
199 | echo ref3=$ref3
|
200 | typeset -n ref3
|
201 | echo ref3=$ref3
|
202 |
|
203 | ## STDOUT:
|
204 | ref=1
|
205 | ref=1
|
206 | ref2=$1
|
207 | ref2=$1
|
208 | ref3=x
|
209 | ref3=foo
|
210 | ## END
|
211 | ## BUG mksh status: 1
|
212 | ## BUG mksh STDOUT:
|
213 | ref=1
|
214 | ref=one
|
215 | ref2=$1
|
216 | ## END
|
217 |
|
218 | #### assign to invalid ref
|
219 | ref=1 # mksh makes this READ-ONLY! Because it's not valid.
|
220 |
|
221 | echo ref=$ref
|
222 | typeset -n ref
|
223 | echo ref=$ref
|
224 |
|
225 | ref=foo
|
226 | echo ref=$ref
|
227 | ## STDOUT:
|
228 | ref=1
|
229 | ref=1
|
230 | ref=foo
|
231 | ## END
|
232 | ## OK mksh status: 2
|
233 | ## OK mksh STDOUT:
|
234 | ref=1
|
235 | ref=
|
236 | ## END
|
237 |
|
238 | #### assign to invalid ref with strict_nameref
|
239 | case $SH in *bash|*mksh) exit ;; esac
|
240 |
|
241 | shopt -s strict_nameref
|
242 |
|
243 | ref=1
|
244 |
|
245 | echo ref=$ref
|
246 | typeset -n ref
|
247 | echo ref=$ref
|
248 |
|
249 | ref=foo
|
250 | echo ref=$ref
|
251 | ## status: 1
|
252 | ## STDOUT:
|
253 | ref=1
|
254 | ## END
|
255 | ## N-I bash/mksh status: 0
|
256 | ## N-I bash/mksh stdout-json: ""
|
257 |
|
258 | #### name ref on Undef cell
|
259 | typeset -n ref
|
260 |
|
261 | # This is technically incorrect: an undefined name shouldn't evaluate to empty
|
262 | # string. mksh doesn't allow it.
|
263 | echo ref=$ref
|
264 |
|
265 | echo nounset
|
266 | set -o nounset
|
267 | echo ref=$ref
|
268 | ## status: 1
|
269 | ## STDOUT:
|
270 | ref=
|
271 | nounset
|
272 | ## END
|
273 | ## OK mksh stdout-json: ""
|
274 |
|
275 | #### assign to empty nameref and invalid nameref
|
276 | typeset -n ref
|
277 | echo ref=$ref
|
278 |
|
279 | # this is a no-op in bash, should be stricter
|
280 | ref=x
|
281 | echo ref=$ref
|
282 |
|
283 | typeset -n ref2=undef
|
284 | echo ref2=$ref2
|
285 | ref2=x
|
286 | echo ref2=$ref2
|
287 |
|
288 | ## STDOUT:
|
289 | ref=
|
290 | ref=
|
291 | ref2=
|
292 | ref2=x
|
293 | ## END
|
294 |
|
295 | # mksh gives a good error: empty nameref target
|
296 | ## OK mksh status: 1
|
297 | ## OK mksh stdout-json: ""
|
298 |
|
299 | #### -n attribute before it has a value
|
300 | typeset -n ref
|
301 |
|
302 | echo ref=$ref
|
303 |
|
304 | # Now that it's a string, it still has the -n attribute
|
305 | x=XX
|
306 | ref=x
|
307 | echo ref=$ref
|
308 |
|
309 | ## STDOUT:
|
310 | ref=
|
311 | ref=XX
|
312 | ## END
|
313 | ## N-I mksh status: 1
|
314 | ## N-I mksh stdout-json: ""
|
315 |
|
316 | #### -n attribute on array is hard error, not a warning
|
317 | x=X
|
318 | typeset -n ref #=x
|
319 | echo hi
|
320 |
|
321 | # bash prints warning: REMOVES the nameref attribute here!
|
322 | ref=(x y)
|
323 | echo ref=$ref
|
324 |
|
325 | ## status: 1
|
326 | ## STDOUT:
|
327 | hi
|
328 | ## END
|
329 | ## N-I mksh status: 1
|
330 | ## N-I mksh stdout-json: ""
|
331 | ## BUG bash status: 0
|
332 | ## BUG bash STDOUT:
|
333 | hi
|
334 | ref=x
|
335 | ## END
|
336 |
|
337 | #### exported nameref
|
338 | x=foo
|
339 | typeset -n -x ref=x
|
340 |
|
341 | # hm bash ignores it but mksh doesn't. maybe disallow it.
|
342 | printenv.py x ref
|
343 | echo ---
|
344 | export x
|
345 | printenv.py x ref
|
346 | ## STDOUT:
|
347 | None
|
348 | x
|
349 | ---
|
350 | foo
|
351 | x
|
352 | ## END
|
353 | ## OK mksh STDOUT:
|
354 | None
|
355 | None
|
356 | ---
|
357 | foo
|
358 | None
|
359 | ## END
|
360 |
|
361 |
|
362 | #### readonly nameref doesn't prevent assigning through it
|
363 |
|
364 | # hm bash also ignores -r when -n is set
|
365 |
|
366 | x=XX
|
367 | typeset -n -r ref=x
|
368 |
|
369 | echo ref=$ref
|
370 |
|
371 | # it feels like I shouldn't be able to mutate this?
|
372 | ref=XXXX
|
373 | echo ref=$ref
|
374 |
|
375 | x=X
|
376 | echo x=$x
|
377 |
|
378 | ## STDOUT:
|
379 | ref=XX
|
380 | ref=XXXX
|
381 | x=X
|
382 | ## END
|
383 |
|
384 | #### readonly var can't be assigned through nameref
|
385 |
|
386 | x=X
|
387 | typeset -n -r ref=x
|
388 |
|
389 | echo ref=$ref
|
390 |
|
391 | # it feels like I shouldn't be able to mutate this?
|
392 | ref=XX
|
393 | echo ref=$ref
|
394 |
|
395 | # now the underling variable is immutable
|
396 | typeset -r x
|
397 |
|
398 | ref=XXX
|
399 | echo ref=$ref
|
400 | echo x=$x
|
401 |
|
402 | ## status: 1
|
403 | ## OK mksh status: 2
|
404 | ## STDOUT:
|
405 | ref=X
|
406 | ref=XX
|
407 | ## END
|
408 |
|
409 | ## OK bash status: 0
|
410 | ## OK bash STDOUT:
|
411 | ref=X
|
412 | ref=XX
|
413 | ref=XX
|
414 | x=XX
|
415 | ## END
|
416 |
|
417 | #### unset nameref
|
418 | x=X
|
419 | typeset -n ref=x
|
420 | echo ref=$ref
|
421 |
|
422 | # this works
|
423 | unset ref
|
424 | echo ref=$ref
|
425 | echo x=$x
|
426 |
|
427 | ## STDOUT:
|
428 | ref=X
|
429 | ref=
|
430 | x=
|
431 | ## END
|
432 |
|
433 | #### Chain of namerefs
|
434 | x=foo
|
435 | typeset -n ref=x
|
436 | typeset -n ref_to_ref=ref
|
437 | echo ref_to_ref=$ref_to_ref
|
438 | echo ref=$ref
|
439 | ## STDOUT:
|
440 | ref_to_ref=foo
|
441 | ref=foo
|
442 | ## END
|
443 |
|
444 | #### Mutually recursive namerefs detected on READ
|
445 | typeset -n ref1=ref2
|
446 | typeset -n ref2=ref1
|
447 | echo defined
|
448 | echo ref1=$ref1
|
449 | echo ref2=$ref1
|
450 | ## status: 1
|
451 | ## STDOUT:
|
452 | defined
|
453 | ## END
|
454 | ## OK mksh stdout-json: ""
|
455 | ## BUG bash status: 0
|
456 | ## BUG bash STDOUT:
|
457 | defined
|
458 | ref1=
|
459 | ref2=
|
460 | ## END
|
461 |
|
462 | #### Mutually recursive namerefs detected on WRITE
|
463 | typeset -n ref1=ref2
|
464 | typeset -n ref2=ref1 # not detected here
|
465 | echo defined $?
|
466 | ref1=z # detected here
|
467 | echo mutated $?
|
468 | ## status: 1
|
469 | ## STDOUT:
|
470 | defined 0
|
471 | ## END
|
472 | ## OK mksh stdout-json: ""
|
473 | ## BUG bash status: 0
|
474 | ## BUG bash STDOUT:
|
475 | defined 0
|
476 | mutated 1
|
477 | ## END
|
478 |
|
479 | #### Dynamic scope with namerefs
|
480 |
|
481 | f3() {
|
482 | local -n ref=$1
|
483 | ref=x
|
484 | }
|
485 |
|
486 | f2() {
|
487 | f3 "$@"
|
488 | }
|
489 |
|
490 | f1() {
|
491 | local F1=F1
|
492 | echo F1=$F1
|
493 | f2 F1
|
494 | echo F1=$F1
|
495 | }
|
496 | f1
|
497 |
|
498 | ## STDOUT:
|
499 | F1=F1
|
500 | F1=x
|
501 | ## END
|
502 |
|
503 |
|
504 | #### change reference itself
|
505 | x=XX
|
506 | y=YY
|
507 | typeset -n ref=x
|
508 | echo ref=$ref
|
509 | echo x=$x
|
510 | echo y=$y
|
511 |
|
512 | echo ----
|
513 | typeset -n ref=y
|
514 | echo ref=$ref
|
515 | echo x=$x
|
516 | echo y=$y
|
517 | echo ----
|
518 | ref=z
|
519 | echo ref=$ref
|
520 | echo x=$x
|
521 | echo y=$y
|
522 |
|
523 | ## STDOUT:
|
524 | ref=XX
|
525 | x=XX
|
526 | y=YY
|
527 | ----
|
528 | ref=YY
|
529 | x=XX
|
530 | y=YY
|
531 | ----
|
532 | ref=z
|
533 | x=XX
|
534 | y=z
|
535 | ## END
|
536 |
|
537 | #### a[2] in nameref
|
538 |
|
539 | typeset -n ref='a[2]'
|
540 | a=(zero one two three)
|
541 | echo ref=$ref
|
542 | ## STDOUT:
|
543 | ref=two
|
544 | ## END
|
545 |
|
546 | #### a[expr] in nameref
|
547 |
|
548 | # this confuses code and data
|
549 | typeset -n ref='a[$(echo 2) + 1]'
|
550 | a=(zero one two three)
|
551 | echo ref=$ref
|
552 | ## STDOUT:
|
553 | ref=three
|
554 | ## END
|
555 |
|
556 | #### a[@] in nameref
|
557 |
|
558 | # this confuses code and data
|
559 | typeset -n ref='a[@]'
|
560 | a=('A B' C)
|
561 | argv.py ref "$ref" # READ through ref works
|
562 | ref=(X Y Z) # WRITE through doesn't work
|
563 | echo status=$?
|
564 | argv.py 'ref[@]' "${ref[@]}"
|
565 | argv.py ref "$ref" # JOINING mangles the array?
|
566 | argv.py 'a[@]' "${a[@]}"
|
567 | ## STDOUT:
|
568 | ['ref', 'A B', 'C']
|
569 | status=1
|
570 | ['ref[@]']
|
571 | ['ref', 'A B', 'C']
|
572 | ['a[@]', 'A B', 'C']
|
573 | ## END
|
574 | ## OK mksh status: 1
|
575 | ## OK mksh stdout-json: ""
|
576 |
|
577 | #### mutate through nameref: ref[0]=
|
578 |
|
579 | # This is DIFFERENT than the nameref itself being 'array[0]' !
|
580 |
|
581 | array=(X Y Z)
|
582 | typeset -n ref=array
|
583 | ref[0]=xx
|
584 | echo ${array[@]}
|
585 | ## STDOUT:
|
586 | xx Y Z
|
587 | ## END
|
588 |
|
589 | #### bad mutation through nameref: ref[0]= where ref is array[0]
|
590 | array=(X Y Z)
|
591 | typeset -n ref='array[0]'
|
592 | ref[0]=foo # error in bash: 'array[0]': not a valid identifier
|
593 | echo status=$?
|
594 | echo ${array[@]}
|
595 | ## STDOUT:
|
596 | status=1
|
597 | X Y Z
|
598 | ## END
|
599 | ## BUG mksh STDOUT:
|
600 | status=0
|
601 | foo Y Z
|
602 | ## END
|
603 |
|
604 | #### @ in nameref isn't supported, unlike in ${!ref}
|
605 |
|
606 | set -- A B
|
607 | typeset -n ref='@' # bash gives an error here
|
608 | echo status=$?
|
609 |
|
610 | echo ref=$ref # bash doesn't give an error here
|
611 | echo status=$?
|
612 | ## status: 1
|
613 | ## stdout-json: ""
|
614 | ## OK bash status: 0
|
615 | ## OK bash STDOUT:
|
616 | status=1
|
617 | ref=
|
618 | status=0
|
619 | ## END
|
620 |
|
621 | #### Unquoted assoc reference on RHS
|
622 | typeset -A bashup_ev_r
|
623 | bashup_ev_r['foo']=bar
|
624 |
|
625 | p() {
|
626 | local s=foo
|
627 | local -n e=bashup_ev["$s"] f=bashup_ev_r["$s"]
|
628 | # Different!
|
629 | #local e=bashup_ev["$s"] f=bashup_ev_r["$s"]
|
630 | argv.py "$f"
|
631 | }
|
632 | p
|
633 | ## STDOUT:
|
634 | ['bar']
|
635 | ## END
|
636 | ## N-I mksh stdout-json: ""
|
637 | ## N-I mksh status: 1
|