1 | ## oils_failures_allowed: 0
|
2 |
|
3 | # Demonstrations for users. Could go in docs.
|
4 |
|
5 | #### GetValue scope and shopt --unset dynamic_scope
|
6 | shopt --set parse_proc
|
7 |
|
8 | f() {
|
9 | echo "sh x=$x"
|
10 | }
|
11 |
|
12 | proc p {
|
13 | echo "oil x=$x"
|
14 | }
|
15 |
|
16 | demo() {
|
17 | local x=dynamic
|
18 | f
|
19 | p
|
20 |
|
21 | shopt --unset dynamic_scope
|
22 | f
|
23 | }
|
24 |
|
25 | x=global
|
26 | demo
|
27 | echo x=$x
|
28 |
|
29 | ## STDOUT:
|
30 | sh x=dynamic
|
31 | oil x=global
|
32 | sh x=global
|
33 | x=global
|
34 | ## END
|
35 |
|
36 |
|
37 | #### SetValue scope and shopt --unset dynamic_scope
|
38 | shopt --set parse_proc
|
39 |
|
40 | f() {
|
41 | x=f
|
42 | }
|
43 |
|
44 | proc p {
|
45 | # x=p not allowed at parse time
|
46 | declare x=p
|
47 | }
|
48 |
|
49 | demo() {
|
50 | local x=stack
|
51 | echo x=$x
|
52 | echo ---
|
53 |
|
54 | f
|
55 | echo f x=$x
|
56 |
|
57 | x=stack
|
58 | p
|
59 | echo p x=$x
|
60 |
|
61 | shopt --unset dynamic_scope
|
62 | x=stack
|
63 | f
|
64 | echo funset x=$x
|
65 | }
|
66 |
|
67 | x=global
|
68 | demo
|
69 |
|
70 | echo ---
|
71 | echo x=$x
|
72 |
|
73 | ## STDOUT:
|
74 | x=stack
|
75 | ---
|
76 | f x=f
|
77 | p x=stack
|
78 | funset x=stack
|
79 | ---
|
80 | x=global
|
81 | ## END
|
82 |
|
83 | #### read scope
|
84 | set -o errexit
|
85 |
|
86 | read-x() {
|
87 | echo dynamic-scope | read x
|
88 | }
|
89 | demo() {
|
90 | local x=42
|
91 | echo x_before=$x
|
92 | read-x
|
93 | echo x_after=$x
|
94 | }
|
95 | demo
|
96 | echo x=$x
|
97 |
|
98 | echo ---
|
99 |
|
100 | # Now 'read x' creates a local variable
|
101 | shopt --unset dynamic_scope
|
102 | demo
|
103 | echo x=$x
|
104 |
|
105 | ## STDOUT:
|
106 | x_before=42
|
107 | x_after=dynamic-scope
|
108 | x=
|
109 | ---
|
110 | x_before=42
|
111 | x_after=42
|
112 | x=
|
113 | ## END
|
114 |
|
115 | #### printf -v x respects dynamic_scope
|
116 | set -o errexit
|
117 |
|
118 | set-x() {
|
119 | printf -v x "%s" dynamic-scope
|
120 | }
|
121 | demo() {
|
122 | local x=42
|
123 | echo x=$x
|
124 | set-x
|
125 | echo x=$x
|
126 | }
|
127 | demo
|
128 | echo x=$x
|
129 |
|
130 | echo ---
|
131 |
|
132 | shopt --unset dynamic_scope # should NOT affect read
|
133 | demo
|
134 | echo x=$x
|
135 |
|
136 | ## STDOUT:
|
137 | x=42
|
138 | x=dynamic-scope
|
139 | x=
|
140 | ---
|
141 | x=42
|
142 | x=42
|
143 | x=
|
144 | ## END
|
145 |
|
146 | #### printf -v a[i] respects dynamic_scope
|
147 | set -o errexit
|
148 |
|
149 | set-item() {
|
150 | printf -v 'a[1]' "%s" dynamic-scope
|
151 | }
|
152 | demo() {
|
153 | local -a a=(41 42 43)
|
154 | echo "a[1]=${a[1]}"
|
155 | set-item
|
156 | echo "a[1]=${a[1]}"
|
157 | }
|
158 | demo
|
159 | echo "a[1]=${a[1]}"
|
160 |
|
161 | echo ---
|
162 |
|
163 | shopt --unset dynamic_scope # should NOT affect read
|
164 | demo
|
165 | echo "a[1]=${a[1]}"
|
166 |
|
167 | ## STDOUT:
|
168 | a[1]=42
|
169 | a[1]=dynamic-scope
|
170 | a[1]=
|
171 | ---
|
172 | a[1]=42
|
173 | a[1]=42
|
174 | a[1]=
|
175 | ## END
|
176 |
|
177 | #### ${undef=a} and shopt --unset dynamic_scope
|
178 |
|
179 | set-x() {
|
180 | : ${x=new}
|
181 | }
|
182 | demo() {
|
183 | local x
|
184 | echo x=$x
|
185 | set-x
|
186 | echo x=$x
|
187 | }
|
188 |
|
189 | demo
|
190 | echo x=$x
|
191 |
|
192 | echo ---
|
193 |
|
194 | # Now this IS affected?
|
195 | shopt --unset dynamic_scope
|
196 | demo
|
197 | echo x=$x
|
198 | ## STDOUT:
|
199 | x=
|
200 | x=new
|
201 | x=
|
202 | ---
|
203 | x=
|
204 | x=
|
205 | x=
|
206 | ## END
|
207 |
|
208 | #### declare -p respects it
|
209 |
|
210 | ___g=G
|
211 |
|
212 | show-vars() {
|
213 | local ___x=X
|
214 | declare -p | grep '___'
|
215 | echo status=$?
|
216 |
|
217 | echo -
|
218 | declare -p ___y | grep '___'
|
219 | echo status=$?
|
220 | }
|
221 |
|
222 | demo() {
|
223 | local ___y=Y
|
224 |
|
225 | show-vars
|
226 | echo ---
|
227 | shopt --unset dynamic_scope
|
228 | show-vars
|
229 | }
|
230 |
|
231 | demo
|
232 |
|
233 | ## STDOUT:
|
234 | declare -- ___g=G
|
235 | declare -- ___x=X
|
236 | declare -- ___y=Y
|
237 | status=0
|
238 | -
|
239 | declare -- ___y=Y
|
240 | status=0
|
241 | ---
|
242 | declare -- ___g=G
|
243 | declare -- ___x=X
|
244 | status=0
|
245 | -
|
246 | status=1
|
247 | ## END
|
248 |
|
249 |
|
250 | #### OshLanguageSetValue constructs
|
251 |
|
252 | f() {
|
253 | (( x = 42 ))
|
254 | }
|
255 | demo() {
|
256 | f
|
257 | echo x=$x
|
258 | }
|
259 |
|
260 | demo
|
261 |
|
262 | echo ---
|
263 |
|
264 | shopt --unset dynamic_scope
|
265 |
|
266 | unset x
|
267 |
|
268 | demo
|
269 |
|
270 | echo --- global
|
271 | echo x=$x
|
272 | ## STDOUT:
|
273 | x=42
|
274 | ---
|
275 | x=
|
276 | --- global
|
277 | x=
|
278 | ## END
|
279 |
|
280 |
|
281 | #### shell assignments 'neutered' inside 'proc'
|
282 | shopt --set parse_proc
|
283 |
|
284 | # They can't mutate globals or anything higher on the stack
|
285 |
|
286 | proc p {
|
287 | declare g=PROC
|
288 | export e=PROC
|
289 | }
|
290 |
|
291 | f() {
|
292 | g=SH
|
293 | export e=SH
|
294 | }
|
295 |
|
296 | e=E
|
297 | g=G
|
298 | p
|
299 | echo e=$e g=$g
|
300 |
|
301 | p
|
302 | echo e=$e g=$g
|
303 |
|
304 | f
|
305 | echo e=$e g=$g
|
306 |
|
307 | ## STDOUT:
|
308 | e=E g=G
|
309 | e=E g=G
|
310 | e=SH g=SH
|
311 | ## END
|
312 |
|
313 | #### setglobal still allows setting globals
|
314 | shopt --set parse_proc
|
315 |
|
316 | proc p {
|
317 | setglobal new_global = 'p'
|
318 | setglobal g = 'p'
|
319 | }
|
320 |
|
321 | var g = 'G'
|
322 |
|
323 | p
|
324 |
|
325 | echo g=$g new_global=$new_global
|
326 | ## STDOUT:
|
327 | g=p new_global=p
|
328 | ## END
|
329 |
|
330 | #### setglobal d[key] inside proc should mutate global (bug #1841)
|
331 |
|
332 | shopt -s ysh:upgrade
|
333 |
|
334 | var g = {}
|
335 |
|
336 | proc mutate {
|
337 | var g = {'local': 1} # shadows global var
|
338 |
|
339 | setglobal g.key = 'mutated'
|
340 | setglobal g['key2'] = 'mutated'
|
341 |
|
342 | echo 'local that is ignored'
|
343 | pp test_ (g)
|
344 | }
|
345 |
|
346 | echo 'BEFORE mutate global'
|
347 | pp test_ (g)
|
348 |
|
349 | mutate
|
350 |
|
351 | echo 'AFTER mutate global'
|
352 | pp test_ (g)
|
353 |
|
354 | ## STDOUT:
|
355 | BEFORE mutate global
|
356 | (Dict) {}
|
357 | local that is ignored
|
358 | (Dict) {"local":1}
|
359 | AFTER mutate global
|
360 | (Dict) {"key":"mutated","key2":"mutated"}
|
361 | ## END
|
362 |
|
363 | #### setglobal a[i] inside proc
|
364 | shopt -s ysh:upgrade
|
365 |
|
366 | var a = [0]
|
367 |
|
368 | proc mutate {
|
369 | var a = [1] # shadows global var
|
370 |
|
371 | echo 'local that is ignored'
|
372 | setglobal a[0] = 42
|
373 |
|
374 | pp test_ (a)
|
375 | }
|
376 |
|
377 | echo 'BEFORE mutate global'
|
378 | pp test_ (a)
|
379 |
|
380 | mutate
|
381 |
|
382 | echo 'AFTER mutate global'
|
383 | pp test_ (a)
|
384 |
|
385 | ## STDOUT:
|
386 | BEFORE mutate global
|
387 | (List) [0]
|
388 | local that is ignored
|
389 | (List) [1]
|
390 | AFTER mutate global
|
391 | (List) [42]
|
392 | ## END
|
393 |
|
394 | #### setglobal a[i] += and d.key +=
|
395 | shopt -s ysh:upgrade
|
396 |
|
397 | var mylist = [0]
|
398 | var mydict = {k: 0}
|
399 |
|
400 | proc mutate {
|
401 | # these locals are ignored
|
402 | var mylist = []
|
403 | var mydict = {}
|
404 |
|
405 | setglobal mylist[0] += 5
|
406 | setglobal mydict['k'] += 5
|
407 | }
|
408 |
|
409 | mutate
|
410 |
|
411 | pp test_ (mylist)
|
412 | pp test_ (mydict)
|
413 |
|
414 | ## STDOUT:
|
415 | (List) [5]
|
416 | (Dict) {"k":5}
|
417 | ## END
|
418 |
|
419 | #### setglobal a[i] - i can be local or global
|
420 | shopt -s ysh:upgrade
|
421 |
|
422 | var mylist = [0, 1]
|
423 | var mydict = {k: 0, n: 1}
|
424 |
|
425 | var i = 0
|
426 | var key = 'k'
|
427 |
|
428 | proc mutate1 {
|
429 | var mylist = [] # IGNORED
|
430 | var mydict = {} # IGNORED
|
431 |
|
432 | var i = 1
|
433 | var key = 'n'
|
434 |
|
435 | setglobal mylist[i] = 11
|
436 | setglobal mydict[key] = 11
|
437 | }
|
438 |
|
439 | # Same thing without locals
|
440 | proc mutate2 {
|
441 | var mylist = [] # IGNORED
|
442 | var mydict = {} # IGNORED
|
443 |
|
444 | setglobal mylist[i] = 22
|
445 | setglobal mydict[key] = 22
|
446 | }
|
447 |
|
448 | mutate1
|
449 |
|
450 | pp test_ (mylist)
|
451 | pp test_ (mydict)
|
452 | echo
|
453 |
|
454 | mutate2
|
455 |
|
456 | pp test_ (mylist)
|
457 | pp test_ (mydict)
|
458 |
|
459 | ## STDOUT:
|
460 | (List) [0,11]
|
461 | (Dict) {"k":0,"n":11}
|
462 |
|
463 | (List) [22,11]
|
464 | (Dict) {"k":22,"n":11}
|
465 | ## END
|
466 |
|
467 | #### unset inside proc uses local scope
|
468 | shopt --set parse_brace
|
469 | shopt --set parse_proc
|
470 |
|
471 | f() {
|
472 | unset x
|
473 | }
|
474 |
|
475 | proc p() {
|
476 | unset x
|
477 | }
|
478 |
|
479 | proc p2() {
|
480 | shopt --set dynamic_scope { # turn it back on
|
481 | unset x
|
482 | }
|
483 | }
|
484 |
|
485 | x=foo
|
486 | f
|
487 | echo f x=$x
|
488 |
|
489 | x=bar
|
490 | p
|
491 | echo p x=$x
|
492 |
|
493 | x=spam
|
494 | p2
|
495 | echo p2 x=$x
|
496 |
|
497 | ## STDOUT:
|
498 | f x=
|
499 | p x=bar
|
500 | p2 x=
|
501 | ## END
|
502 |
|
503 | #### unset composes when you turn on dynamic scope
|
504 | shopt -s ysh:all
|
505 |
|
506 | proc unset-two (v, w) {
|
507 | shopt --set dynamic_scope {
|
508 | unset $v
|
509 | unset $w
|
510 | }
|
511 | }
|
512 |
|
513 | demo() {
|
514 | local x=X
|
515 | local y=Y
|
516 |
|
517 | echo "x=$x y=$y"
|
518 |
|
519 | unset-two x y
|
520 |
|
521 | shopt --unset nounset
|
522 | echo "x=$x y=$y"
|
523 | }
|
524 |
|
525 | demo
|
526 | ## STDOUT:
|
527 | x=X y=Y
|
528 | x= y=
|
529 | ## END
|
530 |
|
531 | #### Temp Bindings
|
532 | shopt --set parse_proc
|
533 |
|
534 | myfunc() {
|
535 | echo myfunc FOO=$FOO
|
536 | }
|
537 | proc myproc() {
|
538 | echo myproc FOO=$FOO
|
539 | }
|
540 |
|
541 | FOO=bar myfunc
|
542 | FOO=bar myproc
|
543 | FOO=bar echo inline FOO=$FOO
|
544 | FOO=bar printenv.py FOO
|
545 |
|
546 | ## STDOUT:
|
547 | myfunc FOO=bar
|
548 | myproc FOO=
|
549 | inline FOO=
|
550 | bar
|
551 | ## END
|
552 |
|
553 | #### cd blocks don't introduce new scopes
|
554 | shopt --set oil:upgrade
|
555 |
|
556 | var x = 42
|
557 | cd / {
|
558 | var y = 0
|
559 | var z = 1
|
560 | echo $x $y $z
|
561 | setvar y = 43
|
562 | }
|
563 | setvar z = 44
|
564 | echo $x $y $z
|
565 |
|
566 | ## STDOUT:
|
567 | 42 0 1
|
568 | 42 43 44
|
569 | ## END
|
570 |
|
571 | #### IFS=: myproc exports when it doesn't need to
|
572 | shopt --set parse_proc
|
573 | shopt --set parse_brace
|
574 |
|
575 | s='xzx zxz'
|
576 |
|
577 | myfunc() {
|
578 | echo myfunc IFS="$IFS"
|
579 | argv.py $s
|
580 | }
|
581 |
|
582 | proc myproc() {
|
583 | echo myproc IFS="$IFS"
|
584 | argv.py $s
|
585 | }
|
586 |
|
587 | IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
|
588 |
|
589 | # default value
|
590 | echo "$IFS" | od -A n -t x1
|
591 |
|
592 | IFS=' z'
|
593 | echo IFS="$IFS"
|
594 |
|
595 | IFS=' x' myfunc
|
596 |
|
597 | # Problem: $IFS in procs only finds GLOBAL values. But when actually
|
598 | # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
|
599 | # Use shvarGet('IFS') instead
|
600 |
|
601 | IFS=' x' myproc
|
602 |
|
603 | # Oil solution to the problem
|
604 | shvar IFS=' x' {
|
605 | myproc
|
606 | }
|
607 |
|
608 | ## STDOUT:
|
609 | :
|
610 | 20 09 0a 0a
|
611 | IFS= z
|
612 | myfunc IFS= x
|
613 | ['', 'z', 'z', 'z']
|
614 | myproc IFS= z
|
615 | ['', 'z', 'z', 'z']
|
616 | myproc IFS= x
|
617 | ['', 'z', 'z', 'z']
|
618 | ## END
|
619 |
|
620 | #### shvar usage
|
621 | shopt --set oil:upgrade
|
622 | shopt --unset errexit
|
623 |
|
624 | # no block
|
625 | shvar
|
626 | echo status=$?
|
627 |
|
628 | shvar { # no arg
|
629 | true
|
630 | }
|
631 | echo status=$?
|
632 |
|
633 | shvar foo { # should be name=value
|
634 | true
|
635 | }
|
636 | echo status=$?
|
637 | ## STDOUT:
|
638 | status=2
|
639 | status=2
|
640 | status=2
|
641 | ## END
|
642 |
|
643 | #### shvar global
|
644 | shopt --set oil:upgrade
|
645 | shopt --unset nounset
|
646 |
|
647 | echo _ESCAPER=$_ESCAPER
|
648 | echo _DIALECT=$_DIALECT
|
649 |
|
650 | shvar _ESCAPER=html _DIALECT=ninja {
|
651 | echo block _ESCAPER=$_ESCAPER
|
652 | echo block _DIALECT=$_DIALECT
|
653 | }
|
654 |
|
655 | echo _ESCAPER=$_ESCAPER
|
656 | echo _DIALECT=$_DIALECT
|
657 |
|
658 | # Now set them
|
659 | _ESCAPER=foo
|
660 | _DIALECT=bar
|
661 |
|
662 | echo ___
|
663 |
|
664 | echo _ESCAPER=$_ESCAPER
|
665 | echo _DIALECT=$_DIALECT
|
666 |
|
667 | shvar _ESCAPER=html _DIALECT=ninja {
|
668 | echo block _ESCAPER=$_ESCAPER
|
669 | echo block _DIALECT=$_DIALECT
|
670 |
|
671 | shvar _ESCAPER=nested {
|
672 | echo nested _ESCAPER=$_ESCAPER
|
673 | echo nested _DIALECT=$_DIALECT
|
674 | }
|
675 | }
|
676 |
|
677 | echo _ESCAPER=$_ESCAPER
|
678 | echo _DIALECT=$_DIALECT
|
679 |
|
680 | ## STDOUT:
|
681 | _ESCAPER=
|
682 | _DIALECT=
|
683 | block _ESCAPER=html
|
684 | block _DIALECT=ninja
|
685 | _ESCAPER=
|
686 | _DIALECT=
|
687 | ___
|
688 | _ESCAPER=foo
|
689 | _DIALECT=bar
|
690 | block _ESCAPER=html
|
691 | block _DIALECT=ninja
|
692 | nested _ESCAPER=nested
|
693 | nested _DIALECT=ninja
|
694 | _ESCAPER=foo
|
695 | _DIALECT=bar
|
696 | ## END
|
697 |
|
698 | #### shvar local
|
699 | shopt --set oil:upgrade # blocks
|
700 | shopt --unset simple_word_eval # test word splitting
|
701 |
|
702 | proc foo {
|
703 | shvar IFS=x MYTEMP=foo {
|
704 | echo IFS="$IFS"
|
705 | argv.py $s
|
706 | echo MYTEMP=${MYTEMP:-undef}
|
707 | }
|
708 | }
|
709 | var s = 'a b c'
|
710 | argv.py $s
|
711 | foo
|
712 | argv.py $s
|
713 | echo MYTEMP=${MYTEMP:-undef}
|
714 | ## STDOUT:
|
715 | ['a', 'b', 'c']
|
716 | IFS=x
|
717 | ['a b c']
|
718 | MYTEMP=foo
|
719 | ['a', 'b', 'c']
|
720 | MYTEMP=undef
|
721 | ## END
|
722 |
|
723 | #### shvar IFS
|
724 | shopt --set oil:upgrade
|
725 |
|
726 | proc myproc() {
|
727 | echo "$IFS" | od -A n -t x1
|
728 |
|
729 | local mylocal=x
|
730 | shvar IFS=w {
|
731 | echo inside IFS="$IFS"
|
732 | echo mylocal="$mylocal" # I do NOT want a new scope!
|
733 | }
|
734 | echo "$IFS" | od -A n -t x1
|
735 | }
|
736 |
|
737 | myproc
|
738 | ## STDOUT:
|
739 | 20 09 0a 0a
|
740 | inside IFS=w
|
741 | mylocal=x
|
742 | 20 09 0a 0a
|
743 | ## END
|
744 |
|
745 | #### shvarGet()
|
746 | shopt --set parse_proc
|
747 |
|
748 | s='xzx zxz'
|
749 |
|
750 | proc myproc {
|
751 | echo wrong IFS="$IFS" # NOT what's used
|
752 | echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
|
753 | argv.py $s
|
754 | }
|
755 |
|
756 | IFS=x
|
757 | IFS=z myproc
|
758 |
|
759 | # null
|
760 | echo $[shvarGet('nonexistent')]
|
761 |
|
762 | ## STDOUT:
|
763 | wrong IFS=x
|
764 | shvar IFS=z
|
765 | ['x', 'x ', 'x']
|
766 | null
|
767 | ## END
|
768 |
|