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 dashglob
154 shopt -s inherit_errexit
155 shopt -s nullglob
156 shopt -s strict_argv
157 shopt -s strict_arith
158 shopt -s strict_array
159 shopt -s strict_backslash
160 shopt -s strict_control_flow
161 shopt -s strict_echo
162 shopt -s strict_errexit
163 shopt -s strict_eval_builtin
164 shopt -s strict_glob
165 shopt -s strict_nameref
166 shopt -s strict_tilde
167 shopt -s strict_word_eval
168 shopt -s verbose_errexit
169 ## END
170
171 #### shopt -s oil:basic
172 shopt -s oil:basic
173 # normal option names
174 shopt -o -p | grep -- ' -o ' | grep -v hashall
175 shopt -p | grep -- ' -s '
176 ## STDOUT:
177 set -o errexit
178 set -o nounset
179 set -o pipefail
180 shopt -s inherit_errexit
181 shopt -s more_errexit
182 shopt -s nullglob
183 shopt -s parse_at
184 shopt -s parse_brace
185 shopt -s parse_index_expr
186 shopt -s parse_paren
187 shopt -s parse_rawc
188 shopt -s simple_test_builtin
189 shopt -s simple_word_eval
190 shopt -s strict_argv
191 shopt -s strict_arith
192 shopt -s strict_array
193 shopt -s strict_backslash
194 shopt -s strict_control_flow
195 shopt -s strict_echo
196 shopt -s strict_errexit
197 shopt -s strict_eval_builtin
198 shopt -s strict_glob
199 shopt -s strict_nameref
200 shopt -s strict_tilde
201 shopt -s strict_word_eval
202 shopt -s verbose_errexit
203 ## END
204
205 #### osh -O oil:basic
206 $SH -O oil:basic -c 'var x = @(one two three); write @x'
207 ## STDOUT:
208 one
209 two
210 three
211 ## END
212
213 #### strict:all includes inherit_errexit
214 shopt -s strict:all
215 echo $(echo one; false; echo two)
216 ## STDOUT:
217 one
218 ## END
219
220 #### parse_set
221 x=init
222
223 set x=42
224 echo x=$x
225 echo argv "$@"
226
227 shopt -s parse_set
228 set x=42
229 builtin set --
230 echo x=$x
231 echo argv "$@"
232
233 ## STDOUT:
234 x=init
235 argv x=42
236 x=42
237 argv
238 ## END
239
240 #### parse_brace: bad block to assignment builtin
241 shopt -s oil:basic
242 # This is a fatal programming error. It's unlike passing an extra arg?
243 local x=y { echo 'bad block' }
244 echo status=$?
245 ## status: 1
246 ## stdout-json: ""
247
248 #### parse_brace: bad block to external program
249 shopt -s oil:basic
250 # This is a fatal programming error. It's unlike passing an extra arg?
251 ls { echo 'bad block' }
252 echo status=$?
253 ## status: 1
254 ## stdout-json: ""
255
256 #### parse_brace: cd { } in pipeline
257 shopt -s oil:basic
258 cd /tmp {
259 pwd
260 pwd
261 } | tr a-z A-Z
262 ## STDOUT:
263 /TMP
264 /TMP
265 ## END
266
267
268 #### parse_brace: if accepts blocks
269 shopt -s oil:basic
270 if test -n foo {
271 echo one
272 }
273 # harder
274 if test -n foo; test -n bar {
275 echo two
276 }
277
278 # just like POSIX shell!
279 if test -n foo;
280
281 test -n bar {
282 echo three
283 }
284
285 if test -z foo {
286 echo if
287 } else {
288 echo else
289 }
290
291 if test -z foo {
292 echo if
293 } elif test -z '' {
294 echo elif
295 } else {
296 echo else
297 }
298
299 echo 'one line'
300 if test -z foo { echo if } elif test -z '' { echo 1 }; if test -n foo { echo 2 };
301
302 echo 'sh syntax'
303 if test -z foo; then echo if; elif test -z ''; then echo 1; fi; if test -n foo { echo 2 };
304
305 # NOTE: This is not alowed because it's like a brace group!
306 # if test -n foo; {
307
308 ## STDOUT:
309 one
310 two
311 three
312 else
313 elif
314 one line
315 1
316 2
317 sh syntax
318 1
319 2
320 ## END
321
322 #### parse_brace: brace group in if condition
323
324 # strict_errexit would make this a RUNTIME error
325 shopt -s parse_brace
326 if { echo one; echo two } {
327 echo three
328 }
329 ## STDOUT:
330 one
331 two
332 three
333 ## END
334
335 #### parse_brace: while/until
336 shopt -s oil:basic
337 while true {
338 echo one
339 break
340 }
341 while true { echo two; break }
342
343 echo 'sh syntax'
344 while true; do echo three; break; done
345 ## STDOUT:
346 one
347 two
348 sh syntax
349 three
350 ## END
351
352 #### parse_brace: for-in loop
353 shopt -s oil:basic
354 for x in one two {
355 echo $x
356 }
357 for x in three { echo $x }
358
359 echo 'sh syntax'
360 for x in four; do echo $x; done
361
362 ## STDOUT:
363 one
364 two
365 three
366 sh syntax
367 four
368 ## END
369
370 #### parse_brace case
371 shopt -s oil:basic
372
373 var files = @(foo.py 'foo test.sh')
374 for name in "${files[@]}" ; do
375 case $name in
376 *.py)
377 echo python
378 ;;
379 *.sh)
380 echo shell
381 ;;
382 esac
383 done
384
385 for name in @files {
386 case $name {
387 (*.py)
388 echo python
389 ;;
390 (*.sh) echo shell ;;
391 }
392 }
393
394 ## STDOUT:
395 python
396 shell
397 python
398 shell
399 ## END
400
401 #### parse_paren: if statement
402 shopt -s oil:basic
403 var x = 1
404 if (x < 42) {
405 echo less
406 }
407
408 if (x < 0) {
409 echo negative
410 } elif (x < 42) {
411 echo less
412 }
413
414 if (x < 0) {
415 echo negative
416 } elif (x < 1) {
417 echo less
418 } else {
419 echo other
420 }
421
422
423 ## STDOUT:
424 less
425 less
426 other
427 ## END
428
429 #### parse_paren: while statement
430 shopt -s oil:basic
431
432 # ksh style
433 var x = 1
434 while (( x < 3 )) {
435 echo $x
436 setvar x += 1
437 }
438 echo 'done ksh'
439
440 # sh style
441 var y = 1
442 while test $y -lt 3 {
443 echo $y
444 setvar y += 1
445 }
446 echo 'done sh'
447
448 # oil
449 var z = 1
450 while (z < 3) {
451 echo $z
452 setvar z += 1
453 }
454 echo 'done oil'
455
456 ## STDOUT:
457 1
458 2
459 done ksh
460 1
461 2
462 done sh
463 1
464 2
465 done oil
466 ## END
467
468 #### while subshell without parse_paren
469 while ( echo one ); do
470 echo two
471 break
472 done
473 ## STDOUT:
474 one
475 two
476 ## END
477
478 #### parse_paren: for loop
479 shopt -s oil:basic
480 var array = @(one two three)
481 for (item in array) {
482 echo $item
483 }
484
485 echo ---
486
487 declare -A A=([k]=v [k2]=v2) # iterate over keys
488 for (key in A) {
489 echo $key
490 } | sort
491 ## STDOUT:
492 one
493 two
494 three
495 ---
496 k
497 k2
498 ## END
499
500 #### parse_equals: allows bare assignment
501 shopt -s oil:all # including nice options
502 x = 1 + 2*3
503 echo $x
504 ## STDOUT:
505 7
506 ## END
507
508 #### parse_equals: disallows ENV=val mycommand
509 shopt -s oil:all
510 ENV=val echo hi
511 ## status: 2
512 ## stdout-json: ""
513
514 #### parse_equals: disallows var=val
515 shopt -s oil:all
516 var=val
517 ## status: 2
518 ## stdout-json: ""
519
520 #### parse_rawc: C strings in @() array literals
521 shopt -s oil:basic
522
523 # BUG: Surprising that this doesn't work because of command mode!
524 var lines=@(c'aa\tbb' c'cc\tdd')
525 echo @lines
526
527 ## STDOUT:
528 ## END
529
530
531 #### parse_paren allows f(x)
532 shopt -s parse_paren
533 func f(x) {
534 echo foo $x
535 }
536 f(42)
537 ## STDOUT:
538 foo 42
539 ## END
540
541 #### nullglob is on with oil:basic
542 write one *.zzz two
543 shopt -s oil:basic
544 write __
545 write one *.zzz two
546 ## STDOUT:
547 one
548 *.zzz
549 two
550 __
551 one
552 two
553 ## END
554
555 #### nullglob is on with oil:all
556 write one *.zzz two
557 shopt -s oil:all
558 write __
559 write one *.zzz two
560 ## STDOUT:
561 one
562 *.zzz
563 two
564 __
565 one
566 two
567 ## END
568
569 #### shopt -s strict_echo
570 foo='one two'
571 echo $foo # bad split then join
572 shopt -s strict_echo
573 echo
574 echo "$foo" # good
575 echo -e "$foo" # still good
576 echo $foo
577 ## status: 2
578 ## STDOUT:
579 one two
580
581 one two
582 one two
583 ## END
584
585 #### shopt -s dashglob
586 mkdir globdir
587 cd globdir
588
589 touch -- file -v
590
591 argv.py *
592
593 shopt -s oil:basic # turns OFF dashglob
594 argv.py *
595
596 shopt -s dashglob # turn it ON
597 argv.py *
598
599 ## STDOUT:
600 ['-v', 'file']
601 ['file']
602 ['-v', 'file']
603 ## END
604
605 #### shopt -s oil:basic turns some options on and others off
606 show() {
607 shopt -p | egrep 'dashglob|strict_arith'
608 }
609
610 show
611 echo ---
612
613 shopt -s strict_arith
614 show
615 echo ---
616
617 shopt -s oil:basic # strict_arith should still be on after this!
618 show
619 echo ---
620
621 shopt -u oil:basic # strict_arith should still be on after this!
622 show
623
624 ## STDOUT:
625 shopt -s dashglob
626 shopt -u strict_arith
627 ---
628 shopt -s dashglob
629 shopt -s strict_arith
630 ---
631 shopt -u dashglob
632 shopt -s strict_arith
633 ---
634 shopt -s dashglob
635 shopt -u strict_arith
636 ## END