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