1 # Test shell execution options.
2
3 #### simple_word_eval doesn't split, glob, or elide empty
4 mkdir mydir
5 touch foo.z bar.z spam.z
6 spaces='a b'
7 dir=mydir
8 glob=*.z
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*.z
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.z', 'foo.z', 'spam.z', 'spam.z']
23 ['-x y', 'z-']
24 ['a b', '*.z', '', 'spam.z']
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 #### simple_word_eval and glob
45 shopt -s simple_word_eval
46
47 # rm -v -f *.ff
48 touch 1.ff 2.ff
49
50 for i in *.ff; do
51 echo $i
52 done
53
54 array=(*.ff)
55 echo "${array[@]}"
56
57 echo *.ff
58
59 ## STDOUT:
60 1.ff
61 2.ff
62 1.ff 2.ff
63 1.ff 2.ff
64 ## END
65
66 #### parse_at
67 words=(a 'b c')
68 argv.py @words
69
70 shopt -s parse_at
71 argv.py @words
72
73 ## STDOUT:
74 ['@words']
75 ['a', 'b c']
76 ## END
77
78 #### parse_at can't be used outside top level
79 f() {
80 shopt -s parse_at
81 echo status=$?
82 }
83 f
84 echo 'should not get here'
85 ## status: 1
86 ## stdout-json: ""
87
88
89 #### sourcing a file that sets parse_at
90 cat >lib.sh <<EOF
91 shopt -s parse_at
92 echo lib.sh
93 EOF
94
95 words=(a 'b c')
96 argv.py @words
97
98 # This has a side effect, which is a bit weird, but not sure how to avoid it.
99 # Maybe we should say that libraries aren't allowed to change it?
100
101 source lib.sh
102 echo 'main.sh'
103
104 argv.py @words
105 ## STDOUT:
106 ['@words']
107 lib.sh
108 main.sh
109 ['a', 'b c']
110 ## END
111
112 #### parse_at can be specified through sh -O
113 $SH +O parse_at -c 'words=(a "b c"); argv.py @words'
114 $SH -O parse_at -c 'words=(a "b c"); argv.py @words'
115 ## STDOUT:
116 ['@words']
117 ['a', 'b c']
118 ## END
119
120 #### @a splices into $0
121 shopt -s simple_word_eval parse_at
122 a=(echo hi)
123 "${a[@]}"
124 @a
125
126 # Bug fix
127 shopt -s strict_array
128
129 "${a[@]}"
130 @a
131 ## STDOUT:
132 hi
133 hi
134 hi
135 hi
136 ## END
137
138 #### ARGV is alias for "$@"
139 shopt -s parse_at
140 argv.py "$@"
141 argv.py @ARGV
142 argv.py "${ARGV[@]}" # not useful, but it works!
143
144 set -- 'a b' c
145 argv.py "$@"
146 argv.py @ARGV
147
148 f() {
149 argv.py "$@"
150 argv.py @ARGV
151 }
152 f 1 '2 3'
153 ## STDOUT:
154 []
155 []
156 []
157 ['a b', 'c']
158 ['a b', 'c']
159 ['1', '2 3']
160 ['1', '2 3']
161 ## END
162
163 #### shopt -s strict:all
164 shopt -s strict:all
165 # normal option names
166 shopt -o -p | grep -- ' -o ' | grep -v hashall
167 shopt -p strict:all
168 ## STDOUT:
169 shopt -s strict_argv
170 shopt -s strict_arith
171 shopt -s strict_array
172 shopt -s strict_control_flow
173 shopt -s strict_errexit
174 shopt -s strict_glob
175 shopt -s strict_nameref
176 shopt -s strict_tilde
177 shopt -s strict_word_eval
178 ## END
179
180 #### shopt -s oil:upgrade
181 shopt -s oil:upgrade
182 # normal option names
183 shopt -o -p | grep -- ' -o ' | grep -v hashall
184 shopt -p oil:upgrade
185 ## STDOUT:
186 set -o errexit
187 set -o nounset
188 set -o pipefail
189 shopt -s command_sub_errexit
190 shopt -u dashglob
191 shopt -s errexit
192 shopt -u expand_aliases
193 shopt -s inherit_errexit
194 shopt -s nounset
195 shopt -s nullglob
196 shopt -s parse_at
197 shopt -s parse_brace
198 shopt -s parse_equals
199 shopt -s parse_paren
200 shopt -s parse_proc
201 shopt -s parse_raw_string
202 shopt -s parse_triple_quote
203 shopt -s pipefail
204 shopt -s process_sub_fail
205 shopt -u redefine_proc
206 shopt -s sigpipe_status_ok
207 shopt -s simple_word_eval
208 shopt -s verbose_errexit
209 shopt -u xtrace_details
210 shopt -s xtrace_rich
211 ## END
212
213 #### osh -O oil:upgrade
214 $SH -O oil:upgrade -c 'var x = %(one two three); write @x'
215 ## STDOUT:
216 one
217 two
218 three
219 ## END
220
221 #### osh -O errexit: use -O everywhere, even for Bourne options
222 $SH -O errexit -c 'shopt -p -o errexit'
223 #$SH -O errexit -c 'shopt -p errexit' # bash doesn't allow this, but Oil does
224 ## STDOUT:
225 set -o errexit
226 ## END
227
228 #### osh -O invalid
229 $SH -O errexit -c 'echo hi'
230 echo status=$?
231 $SH -O invalid -c 'echo hi'
232 echo status=$?
233 ## STDOUT:
234 hi
235 status=0
236 status=2
237 ## END
238
239 #### osh -o new_option is also accepted
240
241 $SH -o nullglob -c 'echo nullglob'
242 echo $? flag nullglob
243
244 $SH -o oil:upgrade -c 'proc p { echo upgrade }; p'
245 echo $? flag oil:upgrade
246
247 # Should disallow these
248
249 set -o nullglob
250 echo $? set builtin nullglob
251 set -o oil:upgrade
252 echo $? set builtin oil:upgrade
253
254 ## STDOUT:
255 nullglob
256 0 flag nullglob
257 upgrade
258 0 flag oil:upgrade
259 2 set builtin nullglob
260 2 set builtin oil:upgrade
261 ## END
262
263
264 #### oil:upgrade includes inherit_errexit
265 shopt -s oil:upgrade
266 echo $(echo one; false; echo two)
267 ## status: 1
268 ## stdout-json: ""
269
270 #### parse_brace: bad block to assignment builtin
271 shopt -s oil:upgrade
272 # This is a fatal programming error. It's unlike passing an extra arg?
273 local x=y { echo 'bad block' }
274 echo status=$?
275 ## status: 1
276 ## stdout-json: ""
277
278 #### parse_brace: bad block to external program
279 shopt -s oil:upgrade
280 # This is a fatal programming error. It's unlike passing an extra arg?
281 ls { echo 'bad block' }
282 echo status=$?
283 ## status: 1
284 ## stdout-json: ""
285
286 #### parse_brace: cd { } in pipeline
287 shopt -s oil:upgrade
288 cd /tmp {
289 pwd
290 pwd
291 } | tr a-z A-Z
292 ## STDOUT:
293 /TMP
294 /TMP
295 ## END
296
297
298 #### parse_brace: if accepts blocks
299 shopt -s oil:upgrade
300 shopt -u errexit # don't need strict_errexit check!
301
302 if test -n foo {
303 echo one
304 }
305 # harder
306 if test -n foo; test -n bar {
307 echo two
308 }
309
310 # just like POSIX shell!
311 if test -n foo;
312
313 test -n bar {
314 echo three
315 }
316
317 if test -z foo {
318 echo if
319 } else {
320 echo else
321 }
322
323 if test -z foo {
324 echo if
325 } elif test -z '' {
326 echo elif
327 } else {
328 echo else
329 }
330
331 echo 'one line'
332 if test -z foo { echo if } elif test -z '' { echo 1 }; if test -n foo { echo 2 };
333
334 echo 'sh syntax'
335 if test -z foo; then echo if; elif test -z ''; then echo 1; fi; if test -n foo { echo 2 };
336
337 # NOTE: This is not alowed because it's like a brace group!
338 # if test -n foo; {
339
340 ## STDOUT:
341 one
342 two
343 three
344 else
345 elif
346 one line
347 1
348 2
349 sh syntax
350 1
351 2
352 ## END
353
354 #### parse_brace: brace group in if condition
355
356 # strict_errexit would make this a RUNTIME error
357 shopt -s parse_brace
358 if { echo one; echo two } {
359 echo three
360 }
361 ## STDOUT:
362 one
363 two
364 three
365 ## END
366
367 #### parse_brace: while/until
368 shopt -s oil:upgrade
369 while true {
370 echo one
371 break
372 }
373 while true { echo two; break }
374
375 echo 'sh syntax'
376 while true; do echo three; break; done
377 ## STDOUT:
378 one
379 two
380 sh syntax
381 three
382 ## END
383
384 #### parse_brace: for-in loop
385 shopt -s oil:upgrade
386 for x in one two {
387 echo $x
388 }
389 for x in three { echo $x }
390
391 echo 'sh syntax'
392 for x in four; do echo $x; done
393
394 ## STDOUT:
395 one
396 two
397 three
398 sh syntax
399 four
400 ## END
401
402 #### parse_brace case
403 shopt -s oil:upgrade
404
405 var files = %(foo.py 'foo test.sh')
406 for name in "${files[@]}" ; do
407 case $name in
408 *.py)
409 echo python
410 ;;
411 *.sh)
412 echo shell
413 ;;
414 esac
415 done
416
417 for name in @files {
418 case $name {
419 (*.py)
420 echo python
421 ;;
422 (*.sh) echo shell ;;
423 }
424 }
425
426 ## STDOUT:
427 python
428 shell
429 python
430 shell
431 ## END
432
433 #### parse_paren: if statement
434 shopt -s oil:upgrade
435 var x = 1
436 if (x < 42) {
437 echo less
438 }
439
440 if (x < 0) {
441 echo negative
442 } elif (x < 42) {
443 echo less
444 }
445
446 if (x < 0) {
447 echo negative
448 } elif (x < 1) {
449 echo less
450 } else {
451 echo other
452 }
453
454
455 ## STDOUT:
456 less
457 less
458 other
459 ## END
460
461 #### parse_paren: while statement
462 shopt -s oil:upgrade
463
464 # ksh style
465 var x = 1
466 while (( x < 3 )) {
467 echo $x
468 setvar x += 1
469 }
470 echo 'done ksh'
471
472 # sh style
473 var y = 1
474 while test $y -lt 3 {
475 echo $y
476 setvar y += 1
477 }
478 echo 'done sh'
479
480 # oil
481 var z = 1
482 while (z < 3) {
483 echo $z
484 setvar z += 1
485 }
486 echo 'done oil'
487
488 ## STDOUT:
489 1
490 2
491 done ksh
492 1
493 2
494 done sh
495 1
496 2
497 done oil
498 ## END
499
500 #### while subshell without parse_paren
501 while ( echo one ); do
502 echo two
503 break
504 done
505 ## STDOUT:
506 one
507 two
508 ## END
509
510 #### nullglob is on with oil:upgrade
511 write one *.zzz two
512 shopt -s oil:upgrade
513 write __
514 write one *.zzz two
515 ## STDOUT:
516 one
517 *.zzz
518 two
519 __
520 one
521 two
522 ## END
523
524 #### nullglob is on with oil:all
525 write one *.zzz two
526 shopt -s oil:all
527 write __
528 write one *.zzz two
529 ## STDOUT:
530 one
531 *.zzz
532 two
533 __
534 one
535 two
536 ## END
537
538 #### shopt -s simple_echo
539 foo='one two'
540 echo $foo # bad split then join
541 shopt -s simple_echo
542 echo
543 echo "$foo" # good
544 echo -e "$foo" # still good
545 echo $foo
546 ## status: 2
547 ## STDOUT:
548 one two
549
550 one two
551 one two
552 ## END
553
554 #### shopt -s dashglob
555 mkdir globdir
556 cd globdir
557
558 touch -- file -v
559
560 argv.py *
561
562 shopt -s oil:upgrade # turns OFF dashglob
563 argv.py *
564
565 shopt -s dashglob # turn it ON
566 argv.py *
567
568 ## STDOUT:
569 ['-v', 'file']
570 ['file']
571 ['-v', 'file']
572 ## END
573
574 #### shopt -s oil:upgrade turns some options on and others off
575 show() {
576 shopt -p | egrep 'dashglob|simple_word_eval'
577 }
578
579 show
580 echo ---
581
582 shopt -s simple_word_eval
583 show
584 echo ---
585
586 shopt -s oil:upgrade # strict_arith should still be on after this!
587 show
588 echo ---
589
590 shopt -u oil:upgrade # strict_arith should still be on after this!
591 show
592
593 ## STDOUT:
594 shopt -s dashglob
595 shopt -u simple_word_eval
596 ---
597 shopt -s dashglob
598 shopt -s simple_word_eval
599 ---
600 shopt -u dashglob
601 shopt -s simple_word_eval
602 ---
603 shopt -s dashglob
604 shopt -u simple_word_eval
605 ## END
606
607 #### oil:upgrade disables aliases
608
609 alias x='echo hi'
610 x
611
612 shopt --set oil:upgrade
613 shopt --unset errexit
614 x
615 echo status=$?
616
617 shopt --set expand_aliases
618 x
619
620 ## STDOUT:
621 hi
622 status=127
623 hi
624 ## END
625
626 #### sigpipe_status_ok
627
628 status_141() {
629 return 141
630 }
631
632 yes | head -n 1
633 echo ${PIPESTATUS[@]}
634
635 # DUMMY
636 yes | status_141
637 echo ${PIPESTATUS[@]}
638
639 shopt --set oil:upgrade # sigpipe_status_ok
640 shopt --unset errexit
641
642 yes | head -n 1
643 echo ${PIPESTATUS[@]}
644
645 # Conveniently, the last 141 isn't changed to 0, because it's run in the
646 # CURRENT process.
647
648 yes | status_141
649 echo ${PIPESTATUS[@]}
650
651 echo background
652 false | status_141 &
653 wait
654 echo status=$? pipestatus=${PIPESTATUS[@]}
655
656 ## STDOUT:
657 y
658 141 0
659 141 141
660 y
661 0 0
662 0 141
663 background
664 status=0 pipestatus=0 141
665 ## END
666
667
668 #### printf | head regression (sigpipe_status_ok)
669
670 shopt --set oil:upgrade
671 shopt --unset errexit
672
673 bad() {
674 /usr/bin/printf '%65538s\n' foo | head -c 1
675 echo external on ${_pipeline_status[@]}
676
677 shopt --unset sigpipe_status_ok {
678 /usr/bin/printf '%65538s\n' foo | head -c 1
679 }
680 echo external off ${_pipeline_status[@]}
681
682 printf '%65538s\n' foo | head -c 1
683 echo builtin on ${_pipeline_status[@]}
684
685 shopt --unset sigpipe_status_ok {
686 printf '%65538s\n' foo | head -c 1
687 }
688 echo builtin off ${_pipeline_status[@]}
689 }
690
691 bad
692 echo finished
693
694 ## STDOUT:
695 external on 0 0
696 external off 141 0
697 builtin on 0 0
698 builtin off 141 0
699 finished
700 ## END
701
702 #### redefine_proc for shell functions
703
704 f() {
705 echo 1
706 }
707 echo 'first'
708
709 f() {
710 echo 2
711 }
712 echo 'second'
713
714 shopt --set oil:upgrade
715 f() {
716 echo 3
717 }
718 echo 'third'
719 ## STDOUT:
720 first
721 second
722 ## END
723 ## status: 1
724
725 #### redefine_proc for procs
726 shopt --set parse_proc
727
728 proc p {
729 echo 1
730 }
731 echo 'first'
732
733 proc p {
734 echo 2
735 }
736 echo 'second'
737
738 shopt --set oil:upgrade
739 proc p {
740 echo 3
741 }
742 echo 'third'
743 ## STDOUT:
744 first
745 second
746 ## END
747 ## status: 1
748
749 #### redefine_proc is on in interactive shell
750
751 $SH -O oil:all -i --rcfile /dev/null -c "
752 source $REPO_ROOT/spec/testdata/module/common.oil
753 source $REPO_ROOT/spec/testdata/module/redefinition.oil
754 log hi
755 "
756 ## STDOUT:
757 common
758 redefinition
759 ## END
760 ## STDERR:
761 hi
762 ## END
763
764
765 #### redefine_module is on in interactive shell
766
767 $SH -O oil:all -i --rcfile /dev/null -c "
768 source $REPO_ROOT/spec/testdata/module/common.oil
769 source $REPO_ROOT/spec/testdata/module/common.oil
770 log hi
771 " 2>stderr.txt
772 echo status=$?
773
774 # Make sure there are two lines
775 wc -l stderr.txt
776 ## STDOUT:
777 common
778 common
779 status=0
780 2 stderr.txt
781 ## END