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