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