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