D0628.extract-global-values.sh (9428B)
1 #!/bin/bash 2 3 _ble_bash=$((BASH_VERSINFO[0]*10000+BASH_VERSINFO[1]*100+BASH_VERSINFO[2])) 4 5 mode=test5d 6 7 #------------------------------------------------------------------------------ 8 # 1 declare -g var とする事でローカル変数を飛び越して 9 # グローバル変数に読み書きできる様になるか? 10 # 11 # →declare -g var=value でグローバル変数に値を設定することはできるが、 12 # この後で $var としても元々あったローカル変数が読み出せる様になるだけである。 13 # 14 15 if [[ $mode == test1 ]]; then 16 var=0 17 18 function call2 { 19 declare -g var=2 20 echo call2: $var 21 } 22 23 function call1 { 24 local var=1 25 call2 26 echo call1: $var 27 } 28 29 echo global: $var 30 call1 31 echo global: $var 32 fi 33 34 #------------------------------------------------------------------------------ 35 # 2 所で export キーワードを用いてもローカル変数になるのだろうか。 36 # 37 # export キーワードを用いた時にはローカル変数にはならない。 38 # local -x を用いればその時限りの環境変数になる。 39 # 40 41 if [[ $mode == test2 ]]; then 42 function call1a { 43 export var=1 44 echo call1: $var 45 } 46 function call1b { 47 local -x var=1 48 echo call1b: $var 49 } 50 51 var=0 52 echo global: $var 53 call1a 54 echo global: $var 55 var=0 56 echo global: $var 57 call1b 58 echo global: $var 59 fi 60 61 #------------------------------------------------------------------------------ 62 # 3 本題に戻る。declare -pg でどの様に出力されるか。 63 # 64 # 何と駄目だ。ローカルの値が出力される。declare -pg でも駄目だし、 65 # また declare -p -g でも駄目だった。 66 # declare -g とすれば -p を指定しなくても全変数の内容が表示される。 67 # と思って試してみたが、この方法でもローカル変数の値が出力される。 68 # というか普通にローカルでしか定義していない変数も出力されている。 69 # 70 71 if [[ $mode == test3 ]]; then 72 var=0 73 74 function call2 { 75 #declare -gp var 76 #declare -pg var 77 declare -p -g var 78 #declare -g 79 } 80 81 function call1 { 82 local var=1 83 local local_var=1 84 call2 85 echo call1: $var 86 } 87 88 echo global: $var 89 call1 90 echo global: $var 91 fi 92 93 #------------------------------------------------------------------------------ 94 # 4 シグナルハンドラから出力させる方法 95 # 96 # うーん。シグナルハンドラの中から見てもローカル変数が定義されている。 97 # 98 99 if [[ $mode == test4 ]]; then 100 function call2 { 101 echo call2: $var 102 declare -p -g var 103 } 104 trap -- 'call2' USR1 105 106 function call1 { 107 local var=1 108 kill -USR1 $BASHPID 109 echo call1: $var 110 } 111 112 var=0 113 echo global: $var 114 call1 115 echo global: $var 116 fi 117 118 #------------------------------------------------------------------------------ 119 # 5 サブシェルで unset を繰り返す方法 120 # 121 # これでアクセスすることができた。 122 # 但し、fork を一回するので遅いという問題はあるが仕方がない。 123 # 124 # 125 126 if [[ $mode == test5 ]]; then 127 function call2 { 128 ( unset -v var 129 echo call2: $var) 130 } 131 132 function call1 { 133 local var=1 134 call2 135 echo call1: $var 136 } 137 138 var=123 139 echo global: $var 140 call1 141 echo global: $var 142 fi 143 144 # 複数階層の場合に正しく var を掘り出せるか。 145 # → OK ちゃんと掘り出せている。 146 if [[ $mode == test5a ]]; then 147 function f1a { 148 ( 149 while [[ ${var+set} ]]; do 150 echo " f1a: var=$var" 151 unset -v var 152 done 153 ) 154 } 155 156 function f1b { 157 local var=f1b 158 echo " f1b: var=$var" 159 f1a 160 echo " f1b: var=$var" 161 } 162 163 function f1c { 164 local var=f1c 165 echo " f1c: var=$var" 166 f1b 167 echo " f1c: var=$var" 168 } 169 170 function f1d { 171 local var=f1d 172 echo " f1d: var=$var" 173 f1c 174 echo " f1d: var=$var" 175 } 176 177 var=global 178 echo "global: var=$var" 179 f1d 180 echo "global: var=$var" 181 fi 182 183 184 # 途中のローカル変数が -r になっていた時、掘り出せるのか? 185 # →駄目。エラーになる。しかも対策しないと無限ループになる。 186 if [[ $mode == test5b ]]; then 187 function f1a { 188 ( 189 count=0 190 count_max=10 191 while [[ ${var+set} ]]; do 192 ((count++<count_max)) || break 193 echo " f1a: var=$var" 194 unset -v var 195 done 196 ) 197 } 198 199 function f1b { 200 local -r var=f1b 201 echo " f1b: var=$var" 202 f1a 203 echo " f1b: var=$var" 204 } 205 206 function f1c { 207 local -r var=f1c 208 echo " f1c: var=$var" 209 f1b 210 echo " f1c: var=$var" 211 } 212 213 var=global 214 echo "global: var=$var" 215 f1c 216 echo "global: var=$var" 217 fi 218 219 # 途中で空の変数定義が存在すると、一番上にまで達したと勘違いして止まるのでは。 220 # 221 # →うーん。一回目・二回目は止まらないけれど、その次には止まる。 222 # つまり local var であっても ${var+set} は反応するが、 223 # それも unset を二回実行すると効かなくなるということ。 224 # 225 226 if [[ $mode == test5c ]]; then 227 function f1a { 228 ( 229 while [[ ${var+set} ]]; do 230 echo " f1a: var=$var" 231 unset -v var 232 done 233 ) 234 } 235 236 function f1b { 237 local var 238 echo " f1b: var=$var" 239 f1a 240 echo " f1b: var=$var" 241 } 242 243 function f1c { 244 local var 245 echo " f1c: var=$var" 246 f1b 247 echo " f1c: var=$var" 248 } 249 250 function f1d { 251 local var 252 echo " f1d: var=$var" 253 f1c 254 echo " f1d: var=$var" 255 } 256 257 var=global 258 echo "global: var=$var" 259 f1d 260 echo "global: var=$var" 261 fi 262 263 264 # declare -g -r を用いてグローバル変数が存在するか分かるのでは? 265 if [[ $mode == test5d ]]; then 266 267 # 先ず、存在しない変数名で declare -g -r すると、 268 # 変数は存在しないことになっているが、unset できなくなる。 269 270 echo $'\e[1m0: test for var1\e[m' 271 declare -g -r var1 272 [[ ${var1+set} ]] && echo "var1 is set; var1=$var1" 273 unset -v var1 274 275 # 存在する変数名では自然な振る舞いをする。 276 # 値が消えるという事もない。unset できなくなる。 277 278 echo $'\e[1m0: test for var2\e[m' 279 var2= 280 declare -g -r var2 281 [[ ${var2+set} ]] && echo "var2 is set; var2=$var2" 282 unset -v var2 283 284 if ((_ble_bash>=40200)); then 285 # 制限: 途中に readonly なローカル変数があるとその変数の値を返す。 286 # しかし、そもそも readonly な変数には問題が多いので ble.sh では使わない。 287 # 注意: bash-4.2 にはバグがあって、グローバル変数が存在しない時に 288 # declare -g -r var とすると、ローカルに新しく読み取り専用の var 変数が作られる。 289 # 現在の実装では問題にならない。 290 function get_global_value { 291 ( 292 __ble_error= 293 __ble_q="'" __ble_Q="'\''" 294 # 補完で 20 階層も関数呼び出しが重なることはなかろう 295 __ble_MaxLoop=20 296 297 for __ble_name; do 298 ((__ble_processed_$__ble_name)) && continue 299 ((__ble_processed_$__ble_name=1)) 300 301 declare -g -r "$__ble_name" 302 303 for ((__ble_i=0;__ble_i<__ble_MaxLoop;__ble_i++)); do 304 # echo "get_global_value: $__ble_name=${!__ble_name}" 305 __ble_value=${!__ble_name} 306 unset -v "$__ble_name" || break 307 done 2>/dev/null 308 309 ((__ble_i==__ble_MaxLoop)) && __ble_error=1 __ble_value=NOT_FOUND 310 311 echo "declare $__ble_name='${__ble_value//$__ble_q/$__ble_Q}'" 312 done 313 314 [[ ! $__ble_error ]] 315 ) 316 } 317 else 318 # 制限: グローバル変数が定義されずローカル変数が定義されているとき、 319 # ローカル変数の値が取得されてしまう。 320 function get_global_value { 321 ( 322 __ble_error= 323 __ble_q="'" __ble_Q="'\''" 324 # 補完で 20 階層も関数呼び出しが重なることはなかろう 325 __ble_MaxLoop=20 326 327 for __ble_name; do 328 ((__ble_processed_$__ble_name)) && continue 329 ((__ble_processed_$__ble_name=1)) 330 331 __ble_value= __ble_found=0 332 for ((__ble_i=0;__ble_i<__ble_MaxLoop;__ble_i++)); do 333 # echo "get_global_value: $__ble_name=${!__ble_name}" 334 [[ ${!__ble_name+set} ]] && __ble_value=${!__ble_name} __ble_found=1 335 unset -v "$__ble_name" 2>/dev/null 336 done 337 338 ((__ble_found)) || __ble_error= __ble_value=NOT_FOUND 339 340 echo "declare $__ble_name='${__ble_value//$__ble_q/$__ble_Q}'" 341 done 342 343 [[ ! $__ble_error ]] 344 ) 345 } 346 fi 347 348 349 function f1a { 350 local var=f1a 351 get_global_value var 352 [[ $var == f1a ]] || echo " f1a: var is broken" 353 } 354 function f1b { 355 local var=f1b 356 f1a 357 [[ $var == f1b ]] || echo " f1b: var is broken" 358 } 359 function f1c { 360 local var=f1c 361 f1b 362 [[ $var == f1c ]] || echo " f1c: var is broken" 363 } 364 365 function f2a { 366 local var 367 get_global_value var 368 [[ $var == '' ]] || echo " f2a: var is broken" 369 } 370 function f2b { 371 local var 372 f2a 373 [[ $var == '' ]] || echo " f2b: var is broken" 374 } 375 function f2c { 376 local var 377 f2b 378 [[ $var == '' ]] || echo " f2c: var is broken" 379 } 380 381 echo $'\e[1m1: var is unset\e[m' 382 f1c 383 f2c 384 echo $'\e[1m2: var is empty\e[m' 385 var= 386 f1c 387 f2c 388 echo $'\e[1m3: var is "global1"\e[m' 389 var=global1 390 f1c 391 f2c 392 echo $'\e[1m4: var is "global2" readonly\e[m' 393 declare -r var=global2 394 f1c 395 f2c 396 fi