| 1 | #!/usr/bin/env bash
 | 
| 2 | #
 | 
| 3 | # Demo of variable scope.
 | 
| 4 | 
 | 
| 5 | #set -o nounset
 | 
| 6 | set -o pipefail
 | 
| 7 | set -o errexit
 | 
| 8 | 
 | 
| 9 | printenv() {
 | 
| 10 |   spec/bin/printenv.py "$@"
 | 
| 11 | }
 | 
| 12 | 
 | 
| 13 | my_global=G1
 | 
| 14 | 
 | 
| 15 | myfunc() {
 | 
| 16 |   # This makes a NEW local variable my_global.
 | 
| 17 |   # Yeah I think this is amenable to static analysis.
 | 
| 18 |   local loc1=L1 my_global loc2=L2
 | 
| 19 | 
 | 
| 20 |   my_global=LL
 | 
| 21 |   echo "my_global in function: $my_global"
 | 
| 22 | 
 | 
| 23 |   loc1=L3
 | 
| 24 |   echo "loc1: $loc1 loc2: $loc2"
 | 
| 25 | 
 | 
| 26 |   # TODO: Add declare
 | 
| 27 | }
 | 
| 28 | 
 | 
| 29 | func2() {
 | 
| 30 |   my_global=G2
 | 
| 31 |   func2_global=G3
 | 
| 32 | 
 | 
| 33 |   local func2_local=A
 | 
| 34 | 
 | 
| 35 |   inner_func() {
 | 
| 36 |     echo "called inner_func"
 | 
| 37 |     #set -o nounset
 | 
| 38 |     # Not defined anymore
 | 
| 39 |     echo "func2_local: $func2_local"
 | 
| 40 |   }
 | 
| 41 | }
 | 
| 42 | 
 | 
| 43 | # Doesn't work until func2 is run
 | 
| 44 | inner_func || echo "inner_func not defined yet"
 | 
| 45 | 
 | 
| 46 | myfunc
 | 
| 47 | echo "my_global: $my_global"
 | 
| 48 | 
 | 
| 49 | func2
 | 
| 50 | 
 | 
| 51 | # This is defined outside
 | 
| 52 | inner_func
 | 
| 53 | 
 | 
| 54 | echo "AFTER mutation my_global: $my_global"
 | 
| 55 | echo "func2_global $func2_global"
 | 
| 56 | 
 | 
| 57 | # These don't leak
 | 
| 58 | echo "loc1: $loc1 loc2: $loc2"
 | 
| 59 | 
 | 
| 60 | # Nothing can be combined.  Only one keyword.  Use declare flags to combine.
 | 
| 61 | combined() {
 | 
| 62 |   local __LOCAL=1
 | 
| 63 |   export __ONE=one
 | 
| 64 |   export local __TWO=two
 | 
| 65 |   export readonly __THREE=three
 | 
| 66 | 
 | 
| 67 |   # does not work!
 | 
| 68 |   local export __FOUR=four
 | 
| 69 |   # does not work!
 | 
| 70 |   readonly export __FIVE=five
 | 
| 71 | 
 | 
| 72 |   readonly local __SIX=six
 | 
| 73 |   echo $SIX
 | 
| 74 | 
 | 
| 75 |   local readonly __SEVEN=seven
 | 
| 76 |   echo $SEVEN
 | 
| 77 |   #echo "readonly: [$readonly]"
 | 
| 78 | 
 | 
| 79 |   # This doesn't work!
 | 
| 80 |   export readonly local __EIGHT=eight
 | 
| 81 | 
 | 
| 82 |   printenv __ONE __TWO __THREE __FOUR __FIVE __SIX __SEVEN __EIGHT
 | 
| 83 |   # export can come first, but local can't come first
 | 
| 84 | 
 | 
| 85 |   # These are both -a
 | 
| 86 |   local __array=(1 2 3)
 | 
| 87 |   local __array2=([a]=1 [b]=2 [c]=3)
 | 
| 88 | 
 | 
| 89 |   # This gets -A
 | 
| 90 |   local -A __array3=([a]=1 [b]=2 [c]=3)
 | 
| 91 | 
 | 
| 92 |   # Doesn't get any flags.  global/local is NOT a flag!  It's about the
 | 
| 93 |   # position in the symbol tables I guess.
 | 
| 94 |   declare -g __global=g
 | 
| 95 | 
 | 
| 96 |   declare -p | grep __
 | 
| 97 | }
 | 
| 98 | 
 | 
| 99 | __GLOBAL=foo
 | 
| 100 | 
 | 
| 101 | combined
 | 
| 102 | echo GLOBAL
 | 
| 103 | declare -p | grep __
 | 
| 104 | 
 | 
| 105 | conditional-local() {
 | 
| 106 |   if test $# -eq 0; then
 | 
| 107 |     echo DEFINING LOCAL
 | 
| 108 |     local x=1
 | 
| 109 |     echo $x
 | 
| 110 |   else
 | 
| 111 |     echo DEFINING GLOBAL
 | 
| 112 |     x=2
 | 
| 113 |     echo $x
 | 
| 114 |   fi
 | 
| 115 | 
 | 
| 116 |   x=3
 | 
| 117 |   echo $x
 | 
| 118 | }
 | 
| 119 | 
 | 
| 120 | conditional-local
 | 
| 121 | echo $x  # x is not defined
 | 
| 122 | 
 | 
| 123 | conditional-local foo
 | 
| 124 | echo $x  # x is not defined
 | 
| 125 | 
 | 
| 126 | 
 |