1 |
#!/usr/bin/env bash |
2 |
# |
3 |
# Tests for builtins having to do with variables: export, readonly, unset, etc. |
4 |
# |
5 |
# Also see assign.test.sh. |
6 |
|
7 |
#### Export sets a global variable |
8 |
# Even after you do export -n, it still exists. |
9 |
f() { export GLOBAL=X; } |
10 |
f |
11 |
echo $GLOBAL |
12 |
printenv.py GLOBAL |
13 |
## stdout-json: "X\nX\n" |
14 |
|
15 |
#### Export sets a global variable that persists after export -n |
16 |
f() { export GLOBAL=X; } |
17 |
f |
18 |
echo $GLOBAL |
19 |
printenv.py GLOBAL |
20 |
export -n GLOBAL |
21 |
echo $GLOBAL |
22 |
printenv.py GLOBAL |
23 |
## STDOUT: |
24 |
X |
25 |
X |
26 |
X |
27 |
None |
28 |
## END |
29 |
## N-I mksh/dash STDOUT: |
30 |
X |
31 |
X |
32 |
## END |
33 |
## N-I mksh status: 1 |
34 |
## N-I dash status: 2 |
35 |
## N-I zsh STDOUT: |
36 |
X |
37 |
X |
38 |
X |
39 |
X |
40 |
## END |
41 |
|
42 |
#### export -n undefined is ignored |
43 |
set -o errexit |
44 |
export -n undef |
45 |
echo status=$? |
46 |
## stdout: status=0 |
47 |
## N-I mksh/dash/zsh stdout-json: "" |
48 |
## N-I mksh status: 1 |
49 |
## N-I dash status: 2 |
50 |
## N-I zsh status: 1 |
51 |
|
52 |
#### Export a global variable and unset it |
53 |
f() { export GLOBAL=X; } |
54 |
f |
55 |
echo $GLOBAL |
56 |
printenv.py GLOBAL |
57 |
unset GLOBAL |
58 |
echo $GLOBAL |
59 |
printenv.py GLOBAL |
60 |
## stdout-json: "X\nX\n\nNone\n" |
61 |
|
62 |
#### Export existing global variables |
63 |
G1=g1 |
64 |
G2=g2 |
65 |
export G1 G2 |
66 |
printenv.py G1 G2 |
67 |
## stdout-json: "g1\ng2\n" |
68 |
|
69 |
#### Export existing local variable |
70 |
f() { |
71 |
local L1=local1 |
72 |
export L1 |
73 |
printenv.py L1 |
74 |
} |
75 |
f |
76 |
printenv.py L1 |
77 |
## stdout-json: "local1\nNone\n" |
78 |
|
79 |
#### Export a local that shadows a global |
80 |
V=global |
81 |
f() { |
82 |
local V=local1 |
83 |
export V |
84 |
printenv.py V |
85 |
} |
86 |
f |
87 |
printenv.py V # exported local out of scope; global isn't exported yet |
88 |
export V |
89 |
printenv.py V # now it's exported |
90 |
## stdout-json: "local1\nNone\nglobal\n" |
91 |
|
92 |
#### Export a variable before defining it |
93 |
export U |
94 |
U=u |
95 |
printenv.py U |
96 |
## stdout: u |
97 |
|
98 |
#### Exporting a parent func variable (dynamic scope) |
99 |
# The algorithm is to walk up the stack and export that one. |
100 |
inner() { |
101 |
export outer_var |
102 |
echo "inner: $outer_var" |
103 |
printenv.py outer_var |
104 |
} |
105 |
outer() { |
106 |
local outer_var=X |
107 |
echo "before inner" |
108 |
printenv.py outer_var |
109 |
inner |
110 |
echo "after inner" |
111 |
printenv.py outer_var |
112 |
} |
113 |
outer |
114 |
## stdout-json: "before inner\nNone\ninner: X\nX\nafter inner\nX\n" |
115 |
|
116 |
#### Dependent export setting |
117 |
# FOO is not respected here either. |
118 |
export FOO=foo v=$(printenv.py FOO) |
119 |
echo "v=$v" |
120 |
## stdout: v=None |
121 |
|
122 |
#### Exporting a variable doesn't change it |
123 |
old=$PATH |
124 |
export PATH |
125 |
new=$PATH |
126 |
test "$old" = "$new" && echo "not changed" |
127 |
## stdout: not changed |
128 |
|
129 |
#### assign to readonly variable |
130 |
# bash doesn't abort unless errexit! |
131 |
readonly foo=bar |
132 |
foo=eggs |
133 |
echo "status=$?" # nothing happens |
134 |
## status: 1 |
135 |
## BUG bash stdout: status=1 |
136 |
## BUG bash status: 0 |
137 |
## OK dash/mksh status: 2 |
138 |
|
139 |
#### assign to readonly variable - errexit |
140 |
set -o errexit |
141 |
readonly foo=bar |
142 |
foo=eggs |
143 |
echo "status=$?" # nothing happens |
144 |
## status: 1 |
145 |
## OK dash/mksh status: 2 |
146 |
|
147 |
#### Unset a variable |
148 |
foo=bar |
149 |
echo foo=$foo |
150 |
unset foo |
151 |
echo foo=$foo |
152 |
## stdout-json: "foo=bar\nfoo=\n" |
153 |
|
154 |
#### Unset exit status |
155 |
V=123 |
156 |
unset V |
157 |
echo status=$? |
158 |
## stdout: status=0 |
159 |
|
160 |
#### Unset nonexistent variable |
161 |
unset ZZZ |
162 |
echo status=$? |
163 |
## stdout: status=0 |
164 |
|
165 |
#### Unset readonly variable |
166 |
# dash and zsh abort the whole program. OSH doesn't? |
167 |
readonly R=foo |
168 |
unset R |
169 |
echo status=$? |
170 |
## status: 0 |
171 |
## stdout: status=1 |
172 |
## OK dash status: 2 |
173 |
## OK dash stdout-json: "" |
174 |
## OK zsh status: 1 |
175 |
## OK zsh stdout-json: "" |
176 |
|
177 |
#### Unset a function without -f |
178 |
f() { |
179 |
echo foo |
180 |
} |
181 |
f |
182 |
unset f |
183 |
f |
184 |
## stdout: foo |
185 |
## status: 127 |
186 |
## N-I dash/mksh/zsh status: 0 |
187 |
## N-I dash/mksh/zsh STDOUT: |
188 |
foo |
189 |
foo |
190 |
## END |
191 |
|
192 |
#### Unset has dynamic scope |
193 |
f() { |
194 |
unset foo |
195 |
} |
196 |
foo=bar |
197 |
echo foo=$foo |
198 |
f |
199 |
echo foo=$foo |
200 |
## stdout-json: "foo=bar\nfoo=\n" |
201 |
|
202 |
#### Unset invalid variable name |
203 |
unset % |
204 |
echo status=$? |
205 |
## STDOUT: |
206 |
status=2 |
207 |
## END |
208 |
## OK bash/mksh STDOUT: |
209 |
status=1 |
210 |
## END |
211 |
## BUG zsh STDOUT: |
212 |
status=0 |
213 |
## END |
214 |
# dash does a hard failure! |
215 |
## OK dash stdout-json: "" |
216 |
## OK dash status: 2 |
217 |
|
218 |
#### Unset nonexistent variable |
219 |
unset _nonexistent__ |
220 |
echo status=$? |
221 |
## STDOUT: |
222 |
status=0 |
223 |
## END |
224 |
|
225 |
#### Unset -v |
226 |
foo() { |
227 |
echo "function foo" |
228 |
} |
229 |
foo=bar |
230 |
unset -v foo |
231 |
echo foo=$foo |
232 |
foo |
233 |
## stdout-json: "foo=\nfunction foo\n" |
234 |
|
235 |
#### Unset -f |
236 |
foo() { |
237 |
echo "function foo" |
238 |
} |
239 |
foo=bar |
240 |
unset -f foo |
241 |
echo foo=$foo |
242 |
foo |
243 |
echo status=$? |
244 |
## stdout-json: "foo=bar\nstatus=127\n" |
245 |
|
246 |
#### Unset array member |
247 |
a=(x y z) |
248 |
unset 'a[1]' |
249 |
echo "${a[@]}" len="${#a[@]}" |
250 |
## stdout: x z len=2 |
251 |
## N-I dash status: 2 |
252 |
## N-I dash stdout-json: "" |
253 |
## OK zsh stdout-json: " y z len=3\n" |
254 |
|
255 |
#### Unset array member with expression |
256 |
i=1 |
257 |
a=(w x y z) |
258 |
unset 'a[ i - 1 ]' a[i+1] # note: can't have space between a and [ |
259 |
echo "${a[@]}" len="${#a[@]}" |
260 |
## stdout: x z len=2 |
261 |
## N-I dash status: 2 |
262 |
## N-I dash stdout-json: "" |
263 |
## N-I zsh status: 1 |
264 |
## N-I zsh stdout-json: "" |
265 |
|
266 |
#### Use local twice |
267 |
f() { |
268 |
local foo=bar |
269 |
local foo |
270 |
echo $foo |
271 |
} |
272 |
f |
273 |
## stdout: bar |
274 |
## BUG zsh STDOUT: |
275 |
foo=bar |
276 |
bar |
277 |
## END |
278 |
|
279 |
#### Local without variable is still unset! |
280 |
set -o nounset |
281 |
f() { |
282 |
local foo |
283 |
echo "[$foo]" |
284 |
} |
285 |
f |
286 |
## stdout-json: "" |
287 |
## status: 1 |
288 |
## OK dash status: 2 |
289 |
# zsh doesn't support nounset? |
290 |
## BUG zsh stdout: [] |
291 |
## BUG zsh status: 0 |
292 |
|
293 |
#### local after readonly |
294 |
f() { |
295 |
readonly y |
296 |
local x=1 y=$(( x )) |
297 |
echo y=$y |
298 |
} |
299 |
f |
300 |
## stdout-json: "" |
301 |
## status: 1 |
302 |
## OK dash status: 2 |
303 |
## BUG bash stdout: y= |
304 |
## BUG bash status: 0 |
305 |
## BUG mksh stdout: y=0 |
306 |
## BUG mksh status: 0 |
307 |
|