sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

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