1 #!/usr/bin/env bash
2
3 #### Env value doesn't persist
4 FOO=foo printenv.py FOO
5 echo [$FOO]
6 ## STDOUT:
7 foo
8 []
9 ## END
10
11 #### Env value with equals
12 FOO=foo=foo printenv.py FOO
13 ## stdout: foo=foo
14
15 #### Env binding can use preceding bindings, but not subsequent ones
16 # This means that for ASSIGNMENT_WORD, on the RHS you invoke the parser again!
17 # Could be any kind of quoted string.
18 FOO="foo" BAR="[$FOO][$BAZ]" BAZ=baz printenv.py FOO BAR BAZ
19 ## STDOUT:
20 foo
21 [foo][]
22 baz
23 ## BUG mksh STDOUT:
24 foo
25 [][]
26 baz
27 ## END
28
29 #### Env value with two quotes
30 FOO='foo'"adjacent" printenv.py FOO
31 ## stdout: fooadjacent
32
33 #### Env value with escaped <
34 FOO=foo\<foo printenv.py FOO
35 ## stdout: foo<foo
36
37 #### FOO=foo echo [foo]
38 FOO=foo echo "[$foo]"
39 ## stdout: []
40
41 #### FOO=foo func
42 func() {
43 echo "[$FOO]"
44 }
45 FOO=foo func
46 ## stdout: [foo]
47
48 #### Multiple temporary envs on the stack
49 g() {
50 echo "$F" "$G1" "$G2"
51 echo '--- g() ---'
52 P=p printenv.py F G1 G2 A P
53 }
54 f() {
55 # NOTE: G1 doesn't pick up binding f, but G2 picks up a.
56 # I don't quite understand why this is, but bash and OSH agree!
57 G1=[$f] G2=[$a] g
58 echo '--- f() ---'
59 printenv.py F G1 G2 A P
60 }
61 a=A
62 F=f f
63 ## STDOUT:
64 f [] [A]
65 --- g() ---
66 f
67 []
68 [A]
69 None
70 p
71 --- f() ---
72 f
73 None
74 None
75 None
76 None
77 ## END
78 ## OK mksh STDOUT:
79 # G1 and G2 somehow persist. I think that is a bug. They should be local to
80 # the G call.
81 f [] [A]
82 --- g() ---
83 f
84 []
85 [A]
86 None
87 p
88 --- f() ---
89 f
90 []
91 [A]
92 None
93 None
94 ## END
95 ## BUG dash STDOUT:
96 # dash sets even less stuff. Doesn't appear correct.
97 f [] [A]
98 --- g() ---
99 None
100 None
101 None
102 None
103 p
104 --- f() ---
105 None
106 None
107 None
108 None
109 None
110 ## END
111
112 #### Escaped = in command name
113 # foo=bar is in the 'spec/bin' dir.
114 foo\=bar
115 ## stdout: HI
116
117 #### Env binding not allowed before compound command
118 # bash gives exit code 2 for syntax error, because of 'do'.
119 # dash gives 0 because there is stuff after for? Should really give an error.
120 # mksh gives acceptable error of 1.
121 FOO=bar for i in a b; do printenv.py $FOO; done
122 ## BUG dash status: 0
123 ## OK mksh status: 1
124 ## status: 2
125
126 #### Trying to run keyword 'for'
127 FOO=bar for
128 ## status: 127
129
130 #### Empty env binding
131 EMPTY= printenv.py EMPTY
132 ## stdout:
133
134 #### Assignment doesn't do word splitting
135 words='one two'
136 a=$words
137 argv.py "$a"
138 ## stdout: ['one two']
139
140 #### Assignment doesn't do glob expansion
141 touch _tmp/z.Z _tmp/zz.Z
142 a=_tmp/*.Z
143 argv.py "$a"
144 ## stdout: ['_tmp/*.Z']
145
146 #### Env binding in readonly/declare disallowed
147 # I'm disallowing this in the oil shell, because it doesn't work in bash!
148 # (v=None vs v=foo)
149 # assert status 2 for parse error, but allow stdout v=None/status 0 for
150 # existing implementations.
151 FOO=foo readonly v=$(printenv.py FOO)
152 echo "v=$v"
153 ## OK bash/dash/mksh stdout: v=None
154 ## OK bash/dash/mksh status: 0
155 ## status: 2
156
157 #### local -a
158 # nixpkgs setup.sh uses this (issue #26)
159 f() {
160 local -a array=(x y z)
161 argv.py "${array[@]}"
162 }
163 f
164 ## stdout: ['x', 'y', 'z']
165 ## N-I dash stdout-json: ""
166 ## N-I dash status: 2
167 ## N-I mksh stdout-json: ""
168 ## N-I mksh status: 1
169
170 #### declare -a
171 # nixpkgs setup.sh uses this (issue #26)
172 declare -a array=(x y z)
173 argv.py "${array[@]}"
174 ## stdout: ['x', 'y', 'z']
175 ## N-I dash stdout-json: ""
176 ## N-I dash status: 2
177 ## N-I mksh stdout-json: ""
178 ## N-I mksh status: 1
179
180 #### typeset -a a[1]=a a[3]=c
181 # declare works the same way in bash, but not mksh.
182 # spaces are NOT allowed here.
183 typeset -a a[1*1]=x a[1+2]=z
184 argv.py "${a[@]}"
185 ## stdout: ['x', 'z']
186 ## N-I dash stdout-json: ""
187 ## N-I dash status: 2
188
189 #### indexed LHS without spaces is allowed
190 a[1 * 1]=x a[ 1 + 2 ]=z
191 argv.py "${a[@]}"
192 ## stdout: ['x', 'z']
193 ## N-I dash stdout-json: ""
194 ## N-I dash status: 2
195
196 #### declare -f exit code indicates function existence
197 func2=x # var names are NOT found
198 declare -f myfunc func2
199 echo $?
200
201 myfunc() { echo myfunc; }
202 # This prints the source code.
203 declare -f myfunc func2 > /dev/null
204 echo $?
205
206 func2() { echo func2; }
207 declare -f myfunc func2 > /dev/null
208 echo $?
209 ## STDOUT:
210 1
211 1
212 0
213 ## END
214 ## N-I dash/mksh STDOUT:
215 127
216 127
217 127
218 ## END
219
220 #### declare -F prints function names
221 add () { expr 4 + 4; }
222 div () { expr 6 / 2; }
223 ek () { echo hello; }
224 __ec () { echo hi; }
225 _ab () { expr 10 % 3; }
226
227 declare -F
228 ## STDOUT:
229 declare -f __ec
230 declare -f _ab
231 declare -f add
232 declare -f div
233 declare -f ek
234 ## END
235 ## N-I dash/mksh stdout-json: ""
236 ## N-I dash/mksh status: 127
237
238 #### declare -p
239 var1() { echo func; } # function names are NOT found.
240 declare -p var1 var2 >/dev/null
241 echo $?
242
243 var1=x
244 declare -p var1 var2 >/dev/null
245 echo $?
246
247 var2=y
248 declare -p var1 var2 >/dev/null
249 echo $?
250 ## STDOUT:
251 1
252 1
253 0
254 ## N-I dash/mksh STDOUT:
255 127
256 127
257 127
258 ## END
259
260 #### typeset -f
261 # mksh implement typeset but not declare
262 typeset -f myfunc func2
263 echo $?
264
265 myfunc() { echo myfunc; }
266 # This prints the source code.
267 typeset -f myfunc func2 > /dev/null
268 echo $?
269
270 func2() { echo func2; }
271 typeset -f myfunc func2 > /dev/null
272 echo $?
273 ## STDOUT:
274 1
275 1
276 0
277 ## END
278 ## N-I dash STDOUT:
279 127
280 127
281 127
282 ## END
283
284 #### typeset -p
285 var1() { echo func; } # function names are NOT found.
286 typeset -p var1 var2 >/dev/null
287 echo $?
288
289 var1=x
290 typeset -p var1 var2 >/dev/null
291 echo $?
292
293 var2=y
294 typeset -p var1 var2 >/dev/null
295 echo $?
296 ## STDOUT:
297 1
298 1
299 0
300 ## BUG mksh STDOUT:
301 # mksh doesn't respect exit codes
302 0
303 0
304 0
305 ## END
306 ## N-I dash STDOUT:
307 127
308 127
309 127
310 ## END
311
312 #### typeset -r makes a string readonly
313 typeset -r s1='12'
314 typeset -r s2='34'
315
316 s1='c'
317 echo status=$?
318 s2='d'
319 echo status=$?
320
321 s1+='e'
322 echo status=$?
323 s2+='f'
324 echo status=$?
325
326 unset s1
327 echo status=$?
328 unset s2
329 echo status=$?
330
331 ## status: 1
332 ## stdout-json: ""
333 ## OK mksh status: 2
334 ## OK bash status: 0
335 ## OK bash STDOUT:
336 status=1
337 status=1
338 status=1
339 status=1
340 status=1
341 status=1
342 ## END
343 ## OK dash status: 0
344 ## N-I dash STDOUT:
345 status=0
346 status=0
347 status=127
348 status=127
349 status=0
350 status=0
351 ## END
352
353 #### typeset -ar makes it readonly
354 typeset -a -r array1=(1 2)
355 typeset -ar array2=(3 4)
356
357 array1=('c')
358 echo status=$?
359 array2=('d')
360 echo status=$?
361
362 array1+=('e')
363 echo status=$?
364 array2+=('f')
365 echo status=$?
366
367 unset array1
368 echo status=$?
369 unset array2
370 echo status=$?
371
372 ## status: 1
373 ## stdout-json: ""
374 ## OK bash status: 0
375 ## OK bash STDOUT:
376 status=1
377 status=1
378 status=1
379 status=1
380 status=1
381 status=1
382 ## END
383 ## N-I dash status: 2
384 ## N-I dash stdout-json: ""
385 ## N-I mksh status: 1
386 ## N-I mksh stdout-json: ""
387
388 #### typeset -x makes it exported
389 typeset -rx PYTHONPATH=lib/
390 printenv.py PYTHONPATH
391 ## STDOUT:
392 lib/
393 ## END
394 ## N-I dash stdout: None
395
396 #### Multiple assignments / array assignments on a line
397 a=1 b[0+0]=2 c=3
398 echo $a $b $c
399 ## stdout: 1 2 3
400 ## N-I dash stdout:
401
402 #### assignments / array assignments not interpreted after 'echo'
403 a=1 echo b[0]=2 c=3
404 ## stdout: b[0]=2 c=3
405
406 #### Env bindings shouldn't contain array assignments
407 a=1 b[0]=2 c=3 printenv.py a b c
408 ## status: 2
409 ## stdout-json: ""
410 ## OK bash STDOUT:
411 1
412 None
413 3
414 ## END
415 ## OK bash status: 0
416 ## BUG mksh STDOUT:
417 1
418 2
419 3
420 ## END
421 ## OK mksh status: 0
422 ## N-I dash stdout-json: ""
423 ## N-I dash status: 127
424
425 #### syntax error in array assignment
426 a=x b[0+]=y c=z
427 echo $a $b $c
428 ## status: 2
429 ## stdout-json: ""
430 ## BUG bash stdout: x
431 ## BUG bash status: 0
432 ## OK mksh stdout-json: ""
433 ## OK mksh status: 1
434 ## N-I dash stdout:
435 ## N-I dash status: 0
436
437 #### dynamic local variables
438 f() {
439 local "$1" # Only x is assigned here
440 echo [$x]
441 echo [$a]
442
443 local $1 # x and a are assigned here
444 echo [$x]
445 echo [$a]
446 }
447 f 'x=y a=b'
448 ## STDOUT:
449 [y a=b]
450 []
451 [y]
452 [b]
453 ## END
454
455 #### 'local x' does not set variable
456 set -o nounset
457 f() {
458 local x
459 echo $x
460 }
461 f
462 ## status: 1
463 ## OK dash status: 2
464
465 #### 'local -a x' does not set variable
466 set -o nounset
467 f() {
468 local -a x
469 echo $x
470 }
471 f
472 ## status: 1
473 ## OK dash status: 2
474
475 #### 'local x' and then array assignment
476 f() {
477 local x
478 x[3]=foo
479 echo ${x[3]}
480 }
481 f
482 ## status: 0
483 ## stdout: foo
484 ## N-I dash status: 2
485 ## N-I dash stdout-json: ""
486
487 #### 'declare -A' and then dict assignment
488 declare -A foo
489 key=bar
490 foo["$key"]=value
491 echo ${foo["bar"]}
492 ## status: 0
493 ## stdout: value
494 ## N-I dash status: 2
495 ## N-I dash stdout-json: ""
496 ## N-I mksh status: 1
497 ## N-I mksh stdout-json: ""
498
499 #### declare -g (bash-specific; bash-completion uses it)
500 f() {
501 declare -g G=42
502 declare L=99
503
504 declare -Ag dict
505 dict["foo"]=bar
506
507 declare -A localdict
508 localdict["spam"]=Eggs
509
510 # For bash-completion
511 eval 'declare -Ag ev'
512 ev["ev1"]=ev2
513 }
514 f
515 argv.py "$G" "$L"
516 argv.py "${dict["foo"]}" "${localdict["spam"]}"
517 argv.py "${ev["ev1"]}"
518 ## STDOUT:
519 ['42', '']
520 ['bar', '']
521 ['ev2']
522 ## END
523 ## N-I dash STDOUT:
524 ['', '']
525
526 ## END
527 ## N-I dash status: 2
528 ## N-I mksh STDOUT:
529 ['', '']
530
531 ## END
532 ## N-I mksh status: 1
533
534 #### declare in an if statement
535 # bug caught by my feature detection snippet in bash-completion
536 if ! foo=bar; then
537 echo BAD
538 fi
539 echo $foo
540 if ! eval 'spam=eggs'; then
541 echo BAD
542 fi
543 echo $spam
544 ## STDOUT:
545 bar
546 eggs
547 ## END
548