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