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