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