1 # Test shell execution options.
2
3 #### simple_word_eval doesn't split, glob, or elide empty
4 mkdir mydir
5 touch foo.txt bar.txt spam.txt
6 spaces='a b'
7 dir=mydir
8 glob=*.txt
9 prefix=sp
10 set -- 'x y' z
11
12 for i in 1 2; do
13 local empty=
14 argv.py $spaces $glob $empty $prefix*.txt
15
16 # arrays still work too, with this weird rule
17 argv.py -"$@"-
18
19 shopt -s simple_word_eval
20 done
21 ## STDOUT:
22 ['a', 'b', 'bar.txt', 'foo.txt', 'spam.txt', 'spam.txt']
23 ['-x y', 'z-']
24 ['a b', '*.txt', '', 'spam.txt']
25 ['-x y', 'z-']
26 ## END
27
28 #### simple_word_eval and strict_array conflict over globs
29 touch foo.txt bar.txt
30 set -- f
31
32 argv.py "$@"*.txt
33 shopt -s simple_word_eval
34 argv.py "$@"*.txt
35 shopt -s strict_array
36 argv.py "$@"*.txt
37
38 ## status: 1
39 ## STDOUT:
40 ['foo.txt']
41 ['foo.txt']
42 ## END
43
44 #### parse_at
45 words=(a 'b c')
46 argv.py @words
47
48 # TODO: This should be parse_oil-at, and only allowed at the top of the file?
49 # Going midway is weird? Then you can't bin/osh -n?
50
51 shopt -s parse_at
52 argv.py @words
53
54 ## STDOUT:
55 ['@words']
56 ['a', 'b c']
57 ## END
58
59 #### parse_at can't be used outside top level
60 f() {
61 shopt -s parse_at
62 echo status=$?
63 }
64 f
65 echo 'should not get here'
66 ## status: 1
67 ## stdout-json: ""
68
69
70 #### sourcing a file that sets parse_at
71 cat >lib.sh <<EOF
72 shopt -s parse_at
73 echo lib.sh
74 EOF
75
76 words=(a 'b c')
77 argv.py @words
78
79 # This has a side effect, which is a bit weird, but not sure how to avoid it.
80 # Maybe we should say that libraries aren't allowed to change it?
81
82 source lib.sh
83 echo 'main.sh'
84
85 argv.py @words
86 ## STDOUT:
87 ['@words']
88 lib.sh
89 main.sh
90 ['a', 'b c']
91 ## END
92
93 #### parse_at can be specified through sh -O
94 $SH +O parse_at -c 'words=(a "b c"); argv.py @words'
95 $SH -O parse_at -c 'words=(a "b c"); argv.py @words'
96 ## STDOUT:
97 ['@words']
98 ['a', 'b c']
99 ## END
100
101 #### @a splices into $0
102 shopt -s simple_word_eval parse_at
103 a=(echo hi)
104 "${a[@]}"
105 @a
106
107 # Bug fix
108 shopt -s strict_array
109
110 "${a[@]}"
111 @a
112 ## STDOUT:
113 hi
114 hi
115 hi
116 hi
117 ## END
118
119 #### ARGV is alias for "$@"
120 shopt -s parse_at
121 argv.py "$@"
122 argv.py @ARGV
123 argv.py "${ARGV[@]}" # not useful, but it works!
124
125 set -- 'a b' c
126 argv.py "$@"
127 argv.py @ARGV
128
129 f() {
130 argv.py "$@"
131 argv.py @ARGV
132 }
133 f 1 '2 3'
134 ## STDOUT:
135 []
136 []
137 []
138 ['a b', 'c']
139 ['a b', 'c']
140 ['1', '2 3']
141 ['1', '2 3']
142 ## END
143
144 #### shopt -s strict:all
145 shopt -s strict:all
146 # normal option names
147 shopt -o -p | grep -- ' -o ' | grep -v hashall
148 shopt -p | grep -- ' -s '
149 ## STDOUT:
150 set -o errexit
151 set -o nounset
152 set -o pipefail
153 shopt -s nullglob
154 shopt -s inherit_errexit
155 shopt -s strict_argv
156 shopt -s strict_arith
157 shopt -s strict_array
158 shopt -s strict_control_flow
159 shopt -s strict_errexit
160 shopt -s strict_eval_builtin
161 shopt -s strict_word_eval
162 shopt -s strict_backslash
163 shopt -s strict_glob
164 ## END
165
166 #### shopt -s oil:basic
167 shopt -s oil:basic
168 # normal option names
169 shopt -o -p | grep -- ' -o ' | grep -v hashall
170 shopt -p | grep -- ' -s '
171 ## STDOUT:
172 set -o errexit
173 set -o nounset
174 set -o pipefail
175 shopt -s inherit_errexit
176 shopt -s strict_argv
177 shopt -s strict_arith
178 shopt -s strict_array
179 shopt -s strict_control_flow
180 shopt -s strict_errexit
181 shopt -s strict_eval_builtin
182 shopt -s strict_word_eval
183 shopt -s strict_backslash
184 shopt -s strict_glob
185 shopt -s simple_word_eval
186 shopt -s more_errexit
187 shopt -s simple_test_builtin
188 shopt -s parse_at
189 shopt -s parse_brace
190 shopt -s parse_index_expr
191 shopt -s parse_paren
192 shopt -s parse_rawc
193 ## END
194
195 #### osh -O oil:basic
196 $SH -O oil:basic -c 'var x = @(one two three); echo @x'
197 ## STDOUT:
198 one two three
199 ## END
200
201 #### strict:all includes inherit_errexit
202 shopt -s strict:all
203 echo $(echo one; false; echo two)
204 ## STDOUT:
205 one
206 ## END
207
208 #### parse_set
209 x=init
210
211 set x=42
212 echo x=$x
213 echo argv "$@"
214
215 shopt -s parse_set
216 set x=42
217 builtin set --
218 echo x=$x
219 echo argv "$@"
220
221 ## STDOUT:
222 x=init
223 argv x=42
224 x=42
225 argv
226 ## END
227
228 #### parse_brace: bad block to assignment builtin
229 shopt -s oil:basic
230 # This is a fatal programming error. It's unlike passing an extra arg?
231 local x=y { echo 'bad block' }
232 echo status=$?
233 ## status: 1
234 ## stdout-json: ""
235
236 #### parse_brace: bad block to external program
237 shopt -s oil:basic
238 # This is a fatal programming error. It's unlike passing an extra arg?
239 ls { echo 'bad block' }
240 echo status=$?
241 ## status: 1
242 ## stdout-json: ""
243
244 #### parse_brace: cd { } in pipeline
245 shopt -s oil:basic
246 cd /tmp {
247 pwd
248 pwd
249 } | tr a-z A-Z
250 ## STDOUT:
251 /TMP
252 /TMP
253 ## END
254
255
256 #### parse_brace: if accepts blocks
257 shopt -s oil:basic
258 if test -n foo {
259 echo one
260 }
261 # harder
262 if test -n foo; test -n bar {
263 echo two
264 }
265
266 # just like POSIX shell!
267 if test -n foo;
268
269 test -n bar {
270 echo three
271 }
272
273 if test -z foo {
274 echo if
275 } else {
276 echo else
277 }
278
279 if test -z foo {
280 echo if
281 } elif test -z '' {
282 echo elif
283 } else {
284 echo else
285 }
286
287 echo 'one line'
288 if test -z foo { echo if } elif test -z '' { echo 1 }; if test -n foo { echo 2 };
289
290 echo 'sh syntax'
291 if test -z foo; then echo if; elif test -z ''; then echo 1; fi; if test -n foo { echo 2 };
292
293 # NOTE: This is not alowed because it's like a brace group!
294 # if test -n foo; {
295
296 ## STDOUT:
297 one
298 two
299 three
300 else
301 elif
302 one line
303 1
304 2
305 sh syntax
306 1
307 2
308 ## END
309
310 #### parse_brace: brace group in if condition
311
312 # strict_errexit would make this a RUNTIME error
313 shopt -s parse_brace
314 if { echo one; echo two } {
315 echo three
316 }
317 ## STDOUT:
318 one
319 two
320 three
321 ## END
322
323 #### parse_brace: while/until
324 shopt -s oil:basic
325 while true {
326 echo one
327 break
328 }
329 while true { echo two; break }
330
331 echo 'sh syntax'
332 while true; do echo three; break; done
333 ## STDOUT:
334 one
335 two
336 sh syntax
337 three
338 ## END
339
340 #### parse_brace: for-in loop
341 shopt -s oil:basic
342 for x in one two {
343 echo $x
344 }
345 for x in three { echo $x }
346
347 echo 'sh syntax'
348 for x in four; do echo $x; done
349
350 ## STDOUT:
351 one
352 two
353 three
354 sh syntax
355 four
356 ## END
357
358 #### parse_brace case
359 shopt -s oil:basic
360
361 var files = @(foo.py 'foo test.sh')
362 for name in "${files[@]}" ; do
363 case $name in
364 *.py)
365 echo python
366 ;;
367 *.sh)
368 echo shell
369 ;;
370 esac
371 done
372
373 for name in @files {
374 case $name {
375 (*.py)
376 echo python
377 ;;
378 (*.sh) echo shell ;;
379 }
380 }
381
382 ## STDOUT:
383 python
384 shell
385 python
386 shell
387 ## END
388
389 #### parse_paren: if statement
390 shopt -s oil:basic
391 var x = 1
392 if (x < 42) {
393 echo less
394 }
395
396 if (x < 0) {
397 echo negative
398 } elif (x < 42) {
399 echo less
400 }
401
402 if (x < 0) {
403 echo negative
404 } elif (x < 1) {
405 echo less
406 } else {
407 echo other
408 }
409
410
411 ## STDOUT:
412 less
413 less
414 other
415 ## END
416
417 #### parse_paren: while statement
418 shopt -s oil:basic
419
420 # ksh style
421 var x = 1
422 while (( x < 3 )) {
423 echo $x
424 setvar x += 1
425 }
426 echo 'done ksh'
427
428 # sh style
429 var y = 1
430 while test $y -lt 3 {
431 echo $y
432 setvar y += 1
433 }
434 echo 'done sh'
435
436 # oil
437 var z = 1
438 while (z < 3) {
439 echo $z
440 setvar z += 1
441 }
442 echo 'done oil'
443
444 ## STDOUT:
445 1
446 2
447 done ksh
448 1
449 2
450 done sh
451 1
452 2
453 done oil
454 ## END
455
456 #### while subshell without parse_paren
457 while ( echo one ); do
458 echo two
459 break
460 done
461 ## STDOUT:
462 one
463 two
464 ## END
465
466 #### parse_paren: for loop
467 shopt -s oil:basic simple_echo
468 var array = @(one two three)
469 for (item in array) {
470 echo $item
471 }
472
473 echo -- ---
474
475 declare -A A=([k]=v [k2]=v2) # iterate over keys
476 for (key in A) {
477 echo $key
478 } | sort
479 ## STDOUT:
480 one
481 two
482 three
483 ---
484 k
485 k2
486 ## END
487
488 #### parse_equals: allows bare assignment
489 shopt -s oil:all # including nice options
490 x = 1 + 2*3
491 echo $x
492 ## STDOUT:
493 7
494 ## END
495
496 #### parse_equals: disallows ENV=val mycommand
497 shopt -s oil:all
498 ENV=val echo hi
499 ## status: 2
500 ## stdout-json: ""
501
502 #### parse_equals: disallows var=val
503 shopt -s oil:all
504 var=val
505 ## status: 2
506 ## stdout-json: ""
507
508 #### parse_rawc: C strings in @() array literals
509 shopt -s oil:basic
510
511 # BUG: Surprising that this doesn't work because of command mode!
512 var lines=@(c'aa\tbb' c'cc\tdd')
513 echo @lines
514
515 ## STDOUT:
516 ## END
517