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 | __g=G
|
210 | show-vars() {
|
211 | local __x=X
|
212 | declare -p | grep '__'
|
213 | echo status=$?
|
214 |
|
215 | echo -
|
216 | declare -p __y | grep '__'
|
217 | echo status=$?
|
218 | }
|
219 |
|
220 | demo() {
|
221 | local __y=Y
|
222 |
|
223 | show-vars
|
224 | echo ---
|
225 | shopt --unset dynamic_scope
|
226 | show-vars
|
227 | }
|
228 |
|
229 | demo
|
230 |
|
231 | ## STDOUT:
|
232 | declare -- __g=G
|
233 | declare -- __x=X
|
234 | declare -- __y=Y
|
235 | status=0
|
236 | -
|
237 | declare -- __y=Y
|
238 | status=0
|
239 | ---
|
240 | declare -- __g=G
|
241 | declare -- __x=X
|
242 | status=0
|
243 | -
|
244 | status=1
|
245 | ## END
|
246 |
|
247 |
|
248 | #### OshLanguageSetValue constructs
|
249 |
|
250 | f() {
|
251 | (( x = 42 ))
|
252 | }
|
253 | demo() {
|
254 | f
|
255 | echo x=$x
|
256 | }
|
257 |
|
258 | demo
|
259 |
|
260 | echo ---
|
261 |
|
262 | shopt --unset dynamic_scope
|
263 |
|
264 | unset x
|
265 |
|
266 | demo
|
267 |
|
268 | echo --- global
|
269 | echo x=$x
|
270 | ## STDOUT:
|
271 | x=42
|
272 | ---
|
273 | x=
|
274 | --- global
|
275 | x=
|
276 | ## END
|
277 |
|
278 |
|
279 | #### shell assignments 'neutered' inside 'proc'
|
280 | shopt --set parse_proc
|
281 |
|
282 | # They can't mutate globals or anything higher on the stack
|
283 |
|
284 | proc p {
|
285 | declare g=PROC
|
286 | export e=PROC
|
287 | }
|
288 |
|
289 | f() {
|
290 | g=SH
|
291 | export e=SH
|
292 | }
|
293 |
|
294 | e=E
|
295 | g=G
|
296 | p
|
297 | echo e=$e g=$g
|
298 |
|
299 | p
|
300 | echo e=$e g=$g
|
301 |
|
302 | f
|
303 | echo e=$e g=$g
|
304 |
|
305 | ## STDOUT:
|
306 | e=E g=G
|
307 | e=E g=G
|
308 | e=SH g=SH
|
309 | ## END
|
310 |
|
311 | #### setglobal still allows setting globals
|
312 | shopt --set parse_proc
|
313 |
|
314 | proc p {
|
315 | setglobal new_global = 'p'
|
316 | setglobal g = 'p'
|
317 | }
|
318 |
|
319 | var g = 'G'
|
320 |
|
321 | p
|
322 |
|
323 | echo g=$g new_global=$new_global
|
324 | ## STDOUT:
|
325 | g=p new_global=p
|
326 | ## END
|
327 |
|
328 | #### setglobal d[key] inside proc should mutate global (bug #1841)
|
329 |
|
330 | shopt -s ysh:upgrade
|
331 |
|
332 | var g = {}
|
333 |
|
334 | proc mutate {
|
335 | var g = {'local': 1} # shadows global var
|
336 |
|
337 | setglobal g.key = 'mutated'
|
338 | setglobal g['key2'] = 'mutated'
|
339 |
|
340 | echo 'local that is ignored'
|
341 | pp line (g)
|
342 | }
|
343 |
|
344 | echo 'BEFORE mutate global'
|
345 | pp line (g)
|
346 |
|
347 | mutate
|
348 |
|
349 | echo 'AFTER mutate global'
|
350 | pp line (g)
|
351 |
|
352 | ## STDOUT:
|
353 | BEFORE mutate global
|
354 | (Dict) {}
|
355 | local that is ignored
|
356 | (Dict) {"local":1}
|
357 | AFTER mutate global
|
358 | (Dict) {"key":"mutated","key2":"mutated"}
|
359 | ## END
|
360 |
|
361 | #### setglobal a[i] inside proc
|
362 | shopt -s ysh:upgrade
|
363 |
|
364 | var a = [0]
|
365 |
|
366 | proc mutate {
|
367 | var a = [1] # shadows global var
|
368 |
|
369 | echo 'local that is ignored'
|
370 | setglobal a[0] = 42
|
371 |
|
372 | pp line (a)
|
373 | }
|
374 |
|
375 | echo 'BEFORE mutate global'
|
376 | pp line (a)
|
377 |
|
378 | mutate
|
379 |
|
380 | echo 'AFTER mutate global'
|
381 | pp line (a)
|
382 |
|
383 | ## STDOUT:
|
384 | BEFORE mutate global
|
385 | (List) [0]
|
386 | local that is ignored
|
387 | (List) [1]
|
388 | AFTER mutate global
|
389 | (List) [42]
|
390 | ## END
|
391 |
|
392 | #### setglobal a[i] += and d.key +=
|
393 | shopt -s ysh:upgrade
|
394 |
|
395 | var mylist = [0]
|
396 | var mydict = {k: 0}
|
397 |
|
398 | proc mutate {
|
399 | # these locals are ignored
|
400 | var mylist = []
|
401 | var mydict = {}
|
402 |
|
403 | setglobal mylist[0] += 5
|
404 | setglobal mydict['k'] += 5
|
405 | }
|
406 |
|
407 | mutate
|
408 |
|
409 | pp line (mylist)
|
410 | pp line (mydict)
|
411 |
|
412 | ## STDOUT:
|
413 | (List) [5]
|
414 | (Dict) {"k":5}
|
415 | ## END
|
416 |
|
417 | #### setglobal a[i] - i can be local or global
|
418 | shopt -s ysh:upgrade
|
419 |
|
420 | var mylist = [0, 1]
|
421 | var mydict = {k: 0, n: 1}
|
422 |
|
423 | var i = 0
|
424 | var key = 'k'
|
425 |
|
426 | proc mutate1 {
|
427 | var mylist = [] # IGNORED
|
428 | var mydict = {} # IGNORED
|
429 |
|
430 | var i = 1
|
431 | var key = 'n'
|
432 |
|
433 | setglobal mylist[i] = 11
|
434 | setglobal mydict[key] = 11
|
435 | }
|
436 |
|
437 | # Same thing without locals
|
438 | proc mutate2 {
|
439 | var mylist = [] # IGNORED
|
440 | var mydict = {} # IGNORED
|
441 |
|
442 | setglobal mylist[i] = 22
|
443 | setglobal mydict[key] = 22
|
444 | }
|
445 |
|
446 | mutate1
|
447 |
|
448 | pp line (mylist)
|
449 | pp line (mydict)
|
450 | echo
|
451 |
|
452 | mutate2
|
453 |
|
454 | pp line (mylist)
|
455 | pp line (mydict)
|
456 |
|
457 | ## STDOUT:
|
458 | (List) [0,11]
|
459 | (Dict) {"k":0,"n":11}
|
460 |
|
461 | (List) [22,11]
|
462 | (Dict) {"k":22,"n":11}
|
463 | ## END
|
464 |
|
465 | #### unset inside proc uses local scope
|
466 | shopt --set parse_brace
|
467 | shopt --set parse_proc
|
468 |
|
469 | f() {
|
470 | unset x
|
471 | }
|
472 |
|
473 | proc p() {
|
474 | unset x
|
475 | }
|
476 |
|
477 | proc p2() {
|
478 | shopt --set dynamic_scope { # turn it back on
|
479 | unset x
|
480 | }
|
481 | }
|
482 |
|
483 | x=foo
|
484 | f
|
485 | echo f x=$x
|
486 |
|
487 | x=bar
|
488 | p
|
489 | echo p x=$x
|
490 |
|
491 | x=spam
|
492 | p2
|
493 | echo p2 x=$x
|
494 |
|
495 | ## STDOUT:
|
496 | f x=
|
497 | p x=bar
|
498 | p2 x=
|
499 | ## END
|
500 |
|
501 | #### unset composes when you turn on dynamic scope
|
502 | shopt -s ysh:all
|
503 |
|
504 | proc unset-two (v, w) {
|
505 | shopt --set dynamic_scope {
|
506 | unset $v
|
507 | unset $w
|
508 | }
|
509 | }
|
510 |
|
511 | demo() {
|
512 | local x=X
|
513 | local y=Y
|
514 |
|
515 | echo "x=$x y=$y"
|
516 |
|
517 | unset-two x y
|
518 |
|
519 | shopt --unset nounset
|
520 | echo "x=$x y=$y"
|
521 | }
|
522 |
|
523 | demo
|
524 | ## STDOUT:
|
525 | x=X y=Y
|
526 | x= y=
|
527 | ## END
|
528 |
|
529 | #### Temp Bindings
|
530 | shopt --set parse_proc
|
531 |
|
532 | myfunc() {
|
533 | echo myfunc FOO=$FOO
|
534 | }
|
535 | proc myproc() {
|
536 | echo myproc FOO=$FOO
|
537 | }
|
538 |
|
539 | FOO=bar myfunc
|
540 | FOO=bar myproc
|
541 | FOO=bar echo inline FOO=$FOO
|
542 | FOO=bar printenv.py FOO
|
543 |
|
544 | ## STDOUT:
|
545 | myfunc FOO=bar
|
546 | myproc FOO=
|
547 | inline FOO=
|
548 | bar
|
549 | ## END
|
550 |
|
551 | #### cd blocks don't introduce new scopes
|
552 | shopt --set oil:upgrade
|
553 |
|
554 | var x = 42
|
555 | cd / {
|
556 | var y = 0
|
557 | var z = 1
|
558 | echo $x $y $z
|
559 | setvar y = 43
|
560 | }
|
561 | setvar z = 44
|
562 | echo $x $y $z
|
563 |
|
564 | ## STDOUT:
|
565 | 42 0 1
|
566 | 42 43 44
|
567 | ## END
|
568 |
|
569 | #### IFS=: myproc exports when it doesn't need to
|
570 | shopt --set parse_proc
|
571 | shopt --set parse_brace
|
572 |
|
573 | s='xzx zxz'
|
574 |
|
575 | myfunc() {
|
576 | echo myfunc IFS="$IFS"
|
577 | argv.py $s
|
578 | }
|
579 |
|
580 | proc myproc() {
|
581 | echo myproc IFS="$IFS"
|
582 | argv.py $s
|
583 | }
|
584 |
|
585 | IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
|
586 |
|
587 | # default value
|
588 | echo "$IFS" | od -A n -t x1
|
589 |
|
590 | IFS=' z'
|
591 | echo IFS="$IFS"
|
592 |
|
593 | IFS=' x' myfunc
|
594 |
|
595 | # Problem: $IFS in procs only finds GLOBAL values. But when actually
|
596 | # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
|
597 | # Use shvarGet('IFS') instead
|
598 |
|
599 | IFS=' x' myproc
|
600 |
|
601 | # Oil solution to the problem
|
602 | shvar IFS=' x' {
|
603 | myproc
|
604 | }
|
605 |
|
606 | ## STDOUT:
|
607 | :
|
608 | 20 09 0a 0a
|
609 | IFS= z
|
610 | myfunc IFS= x
|
611 | ['', 'z', 'z', 'z']
|
612 | myproc IFS= z
|
613 | ['', 'z', 'z', 'z']
|
614 | myproc IFS= x
|
615 | ['', 'z', 'z', 'z']
|
616 | ## END
|
617 |
|
618 | #### shvar usage
|
619 | shopt --set oil:upgrade
|
620 | shopt --unset errexit
|
621 |
|
622 | # no block
|
623 | shvar
|
624 | echo status=$?
|
625 |
|
626 | shvar { # no arg
|
627 | true
|
628 | }
|
629 | echo status=$?
|
630 |
|
631 | shvar foo { # should be name=value
|
632 | true
|
633 | }
|
634 | echo status=$?
|
635 | ## STDOUT:
|
636 | status=2
|
637 | status=2
|
638 | status=2
|
639 | ## END
|
640 |
|
641 | #### shvar global
|
642 | shopt --set oil:upgrade
|
643 | shopt --unset nounset
|
644 |
|
645 | echo _ESCAPER=$_ESCAPER
|
646 | echo _DIALECT=$_DIALECT
|
647 |
|
648 | shvar _ESCAPER=html _DIALECT=ninja {
|
649 | echo block _ESCAPER=$_ESCAPER
|
650 | echo block _DIALECT=$_DIALECT
|
651 | }
|
652 |
|
653 | echo _ESCAPER=$_ESCAPER
|
654 | echo _DIALECT=$_DIALECT
|
655 |
|
656 | # Now set them
|
657 | _ESCAPER=foo
|
658 | _DIALECT=bar
|
659 |
|
660 | echo ___
|
661 |
|
662 | echo _ESCAPER=$_ESCAPER
|
663 | echo _DIALECT=$_DIALECT
|
664 |
|
665 | shvar _ESCAPER=html _DIALECT=ninja {
|
666 | echo block _ESCAPER=$_ESCAPER
|
667 | echo block _DIALECT=$_DIALECT
|
668 |
|
669 | shvar _ESCAPER=nested {
|
670 | echo nested _ESCAPER=$_ESCAPER
|
671 | echo nested _DIALECT=$_DIALECT
|
672 | }
|
673 | }
|
674 |
|
675 | echo _ESCAPER=$_ESCAPER
|
676 | echo _DIALECT=$_DIALECT
|
677 |
|
678 | ## STDOUT:
|
679 | _ESCAPER=
|
680 | _DIALECT=
|
681 | block _ESCAPER=html
|
682 | block _DIALECT=ninja
|
683 | _ESCAPER=
|
684 | _DIALECT=
|
685 | ___
|
686 | _ESCAPER=foo
|
687 | _DIALECT=bar
|
688 | block _ESCAPER=html
|
689 | block _DIALECT=ninja
|
690 | nested _ESCAPER=nested
|
691 | nested _DIALECT=ninja
|
692 | _ESCAPER=foo
|
693 | _DIALECT=bar
|
694 | ## END
|
695 |
|
696 | #### shvar local
|
697 | shopt --set oil:upgrade # blocks
|
698 | shopt --unset simple_word_eval # test word splitting
|
699 |
|
700 | proc foo {
|
701 | shvar IFS=x MYTEMP=foo {
|
702 | echo IFS="$IFS"
|
703 | argv.py $s
|
704 | echo MYTEMP=${MYTEMP:-undef}
|
705 | }
|
706 | }
|
707 | var s = 'a b c'
|
708 | argv.py $s
|
709 | foo
|
710 | argv.py $s
|
711 | echo MYTEMP=${MYTEMP:-undef}
|
712 | ## STDOUT:
|
713 | ['a', 'b', 'c']
|
714 | IFS=x
|
715 | ['a b c']
|
716 | MYTEMP=foo
|
717 | ['a', 'b', 'c']
|
718 | MYTEMP=undef
|
719 | ## END
|
720 |
|
721 | #### shvar IFS
|
722 | shopt --set oil:upgrade
|
723 |
|
724 | proc myproc() {
|
725 | echo "$IFS" | od -A n -t x1
|
726 |
|
727 | local mylocal=x
|
728 | shvar IFS=w {
|
729 | echo inside IFS="$IFS"
|
730 | echo mylocal="$mylocal" # I do NOT want a new scope!
|
731 | }
|
732 | echo "$IFS" | od -A n -t x1
|
733 | }
|
734 |
|
735 | myproc
|
736 | ## STDOUT:
|
737 | 20 09 0a 0a
|
738 | inside IFS=w
|
739 | mylocal=x
|
740 | 20 09 0a 0a
|
741 | ## END
|
742 |
|
743 | #### shvarGet()
|
744 | shopt --set parse_proc
|
745 |
|
746 | s='xzx zxz'
|
747 |
|
748 | proc myproc {
|
749 | echo wrong IFS="$IFS" # NOT what's used
|
750 | echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
|
751 | argv.py $s
|
752 | }
|
753 |
|
754 | IFS=x
|
755 | IFS=z myproc
|
756 |
|
757 | # null
|
758 | echo $[shvarGet('nonexistent')]
|
759 |
|
760 | ## STDOUT:
|
761 | wrong IFS=x
|
762 | shvar IFS=z
|
763 | ['x', 'x ', 'x']
|
764 | null
|
765 | ## END
|
766 |
|