OILS / spec / ysh-options.test.sh View on Github | oilshell.org

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