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