1 #!/bin/bash
2 #
3 # Extended assignment language, e.g. typeset, declare, arrays, etc.
4 # Things that dash doesn't support.
5
6 #### local -a
7 # nixpkgs setup.sh uses this (issue #26)
8 f() {
9 local -a array=(x y z)
10 argv.py "${array[@]}"
11 }
12 f
13 ## stdout: ['x', 'y', 'z']
14 ## N-I mksh stdout-json: ""
15 ## N-I mksh status: 1
16
17 #### declare -a
18 # nixpkgs setup.sh uses this (issue #26)
19 declare -a array=(x y z)
20 argv.py "${array[@]}"
21 ## stdout: ['x', 'y', 'z']
22 ## N-I mksh stdout-json: ""
23 ## N-I mksh status: 1
24
25 #### indexed LHS with spaces (not allowed in OSH)
26 a[1 * 1]=x a[ 1 + 2 ]=z
27 echo status=$?
28 argv.py "${a[@]}"
29 ## STDOUT:
30 status=0
31 ['x', 'z']
32 ## END
33 ## N-I osh STDOUT:
34 status=127
35 []
36 ## END
37
38 #### declare -f exit code indicates function existence
39 func2=x # var names are NOT found
40 declare -f myfunc func2
41 echo $?
42
43 myfunc() { echo myfunc; }
44 # This prints the source code.
45 declare -f myfunc func2 > /dev/null
46 echo $?
47
48 func2() { echo func2; }
49 declare -f myfunc func2 > /dev/null
50 echo $?
51 ## STDOUT:
52 1
53 1
54 0
55 ## END
56 ## N-I mksh STDOUT:
57 127
58 127
59 127
60 ## END
61
62 #### declare -F prints function names
63 add () { expr 4 + 4; }
64 div () { expr 6 / 2; }
65 ek () { echo hello; }
66 __ec () { echo hi; }
67 _ab () { expr 10 % 3; }
68
69 declare -F
70 ## STDOUT:
71 declare -f __ec
72 declare -f _ab
73 declare -f add
74 declare -f div
75 declare -f ek
76 ## END
77 ## N-I mksh stdout-json: ""
78 ## N-I mksh status: 127
79
80 #### declare -p
81 var1() { echo func; } # function names are NOT found.
82 declare -p var1 var2 >/dev/null
83 echo $?
84
85 var1=x
86 declare -p var1 var2 >/dev/null
87 echo $?
88
89 var2=y
90 declare -p var1 var2 >/dev/null
91 echo $?
92 ## STDOUT:
93 1
94 1
95 0
96 ## N-I mksh STDOUT:
97 127
98 127
99 127
100 ## END
101
102 #### typeset -f
103 # mksh implement typeset but not declare
104 typeset -f myfunc func2
105 echo $?
106
107 myfunc() { echo myfunc; }
108 # This prints the source code.
109 typeset -f myfunc func2 > /dev/null
110 echo $?
111
112 func2() { echo func2; }
113 typeset -f myfunc func2 > /dev/null
114 echo $?
115 ## STDOUT:
116 1
117 1
118 0
119 ## END
120
121 #### typeset -p
122 var1() { echo func; } # function names are NOT found.
123 typeset -p var1 var2 >/dev/null
124 echo $?
125
126 var1=x
127 typeset -p var1 var2 >/dev/null
128 echo $?
129
130 var2=y
131 typeset -p var1 var2 >/dev/null
132 echo $?
133 ## STDOUT:
134 1
135 1
136 0
137 ## BUG mksh STDOUT:
138 # mksh doesn't respect exit codes
139 0
140 0
141 0
142 ## END
143
144 #### typeset -r makes a string readonly
145 typeset -r s1='12'
146 typeset -r s2='34'
147
148 s1='c'
149 echo status=$?
150 s2='d'
151 echo status=$?
152
153 s1+='e'
154 echo status=$?
155 s2+='f'
156 echo status=$?
157
158 unset s1
159 echo status=$?
160 unset s2
161 echo status=$?
162
163 ## status: 1
164 ## stdout-json: ""
165 ## OK mksh status: 2
166 ## OK bash status: 0
167 ## OK bash STDOUT:
168 status=1
169 status=1
170 status=1
171 status=1
172 status=1
173 status=1
174 ## END
175
176 #### typeset -ar makes it readonly
177 typeset -a -r array1=(1 2)
178 typeset -ar array2=(3 4)
179
180 array1=('c')
181 echo status=$?
182 array2=('d')
183 echo status=$?
184
185 array1+=('e')
186 echo status=$?
187 array2+=('f')
188 echo status=$?
189
190 unset array1
191 echo status=$?
192 unset array2
193 echo status=$?
194
195 ## status: 1
196 ## stdout-json: ""
197 ## OK bash status: 0
198 ## OK bash STDOUT:
199 status=1
200 status=1
201 status=1
202 status=1
203 status=1
204 status=1
205 ## END
206 ## N-I mksh status: 1
207 ## N-I mksh stdout-json: ""
208
209 #### typeset -x makes it exported
210 typeset -rx PYTHONPATH=lib/
211 printenv.py PYTHONPATH
212 ## STDOUT:
213 lib/
214 ## END
215
216 #### Multiple assignments / array assignments on a line
217 a=1 b[0+0]=2 c=3
218 echo $a ${b[@]} $c
219 ## stdout: 1 2 3
220
221 #### Env bindings shouldn't contain array assignments
222 a=1 b[0]=2 c=3 printenv.py a b c
223 ## status: 2
224 ## stdout-json: ""
225 ## OK bash STDOUT:
226 1
227 None
228 3
229 ## END
230 ## OK bash status: 0
231 ## BUG mksh STDOUT:
232 1
233 2
234 3
235 ## END
236 ## OK mksh status: 0
237
238 #### syntax error in array assignment
239 a=x b[0+]=y c=z
240 echo $a $b $c
241 ## status: 2
242 ## stdout-json: ""
243 ## BUG bash stdout: x
244 ## BUG bash status: 0
245 ## OK mksh stdout-json: ""
246 ## OK mksh status: 1
247
248 #### declare -g (bash-specific; bash-completion uses it)
249 f() {
250 declare -g G=42
251 declare L=99
252
253 declare -Ag dict
254 dict["foo"]=bar
255
256 declare -A localdict
257 localdict["spam"]=Eggs
258
259 # For bash-completion
260 eval 'declare -Ag ev'
261 ev["ev1"]=ev2
262 }
263 f
264 argv.py "$G" "$L"
265 argv.py "${dict["foo"]}" "${localdict["spam"]}"
266 argv.py "${ev["ev1"]}"
267 ## STDOUT:
268 ['42', '']
269 ['bar', '']
270 ['ev2']
271 ## END
272 ## N-I mksh STDOUT:
273 ['', '']
274 ## END
275 ## N-I mksh status: 1
276
277 #### myvar=typeset (another form of dynamic assignment)
278 myvar=typeset
279 x='a b'
280 $myvar x=$x
281 echo $x
282 ## STDOUT:
283 a
284 ## END
285 ## OK osh STDOUT:
286 a b
287 ## END
288
289 #### dynamic array parsing is not allowed
290 code='x=(1 2 3)'
291 typeset -a "$code" # note: -a flag is required
292 echo status=$?
293 argv.py "$x"
294 ## STDOUT:
295 status=1
296 ['']
297 ## END
298 ## OK mksh STDOUT:
299 status=0
300 ['(1 2 3)']
301 ## END
302 # bash allows it
303 ## OK bash STDOUT:
304 status=0
305 ['1']
306 ## END
307
308 #### dynamic flag in array in assign builtin
309 typeset b
310 b=(unused1 unused2) # this works in mksh
311
312 a=(x 'foo=F' 'bar=B')
313 typeset -"${a[@]}"
314 echo foo=$foo
315 echo bar=$bar
316 printenv.py foo
317 printenv.py bar
318
319 # syntax error in mksh! But works in bash and zsh.
320 #typeset -"${a[@]}" b=(spam eggs)
321 #echo "length of b = ${#b[@]}"
322 #echo "b[0]=${b[0]}"
323 #echo "b[1]=${b[1]}"
324
325 ## STDOUT:
326 foo=F
327 bar=B
328 F
329 B
330 ## END
331
332 #### typeset +x
333 export e=E
334 printenv.py e
335 typeset +x e=E2
336 printenv.py e # no longer exported
337 ## STDOUT:
338 E
339 None
340 ## END
341
342 #### typeset +r removes read-only attribute
343 readonly r=r1
344 echo r=$r
345
346 # clear the readonly flag. Why is this accepted in bash/mksh, but doesn't do
347 # anything?
348 typeset +r r=r2
349 echo r=$r
350
351 r=r3
352 echo r=$r
353
354 ## status: 0
355 ## STDOUT:
356 r=r1
357 r=r2
358 r=r3
359 ## END
360
361 # bash doesn't allow you to unset
362 ## OK mksh status: 2
363 ## OK mksh STDOUT:
364 r=r1
365 ## END
366
367 # bash doesn't allow you to unset
368 ## OK bash status: 0
369 ## OK bash STDOUT:
370 r=r1
371 r=r1
372 r=r1
373 ## END