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