1 # Test shell execution options.
2
3 #### simple_word_eval doesn't split, glob, or elide empty
4 mkdir mydir
5 touch foo.txt bar.txt spam.txt
6 spaces='a b'
7 dir=mydir
8 glob=*.txt
9 prefix=sp
10 set -- 'x y' z
11
12 for i in 1 2; do
13 local empty=
14 argv.py $spaces $glob $empty $prefix*.txt
15
16 # arrays still work too, with this weird rule
17 argv.py -"$@"-
18
19 shopt -s simple_word_eval
20 done
21 ## STDOUT:
22 ['a', 'b', 'bar.txt', 'foo.txt', 'spam.txt', 'spam.txt']
23 ['-x y', 'z-']
24 ['a b', '*.txt', '', 'spam.txt']
25 ['-x y', 'z-']
26 ## END
27
28 #### simple_word_eval and strict_array conflict over globs
29 touch foo.txt bar.txt
30 set -- f
31
32 argv.py "$@"*.txt
33 shopt -s simple_word_eval
34 argv.py "$@"*.txt
35 shopt -s strict_array
36 argv.py "$@"*.txt
37
38 ## status: 1
39 ## STDOUT:
40 ['foo.txt']
41 ['foo.txt']
42 ## END
43
44 #### parse_at
45 words=(a 'b c')
46 argv.py @words
47
48 shopt -s parse_at
49 argv.py @words
50
51 ## STDOUT:
52 ['@words']
53 ['a', 'b c']
54 ## END
55
56 #### parse_at can't be used outside top level
57 f() {
58 shopt -s parse_at
59 echo status=$?
60 }
61 f
62 echo 'should not get here'
63 ## status: 1
64 ## stdout-json: ""
65
66
67 #### sourcing a file that sets parse_at
68 cat >lib.sh <<EOF
69 shopt -s parse_at
70 echo lib.sh
71 EOF
72
73 words=(a 'b c')
74 argv.py @words
75
76 # This has a side effect, which is a bit weird, but not sure how to avoid it.
77 # Maybe we should say that libraries aren't allowed to change it?
78
79 source lib.sh
80 echo 'main.sh'
81
82 argv.py @words
83 ## STDOUT:
84 ['@words']
85 lib.sh
86 main.sh
87 ['a', 'b c']
88 ## END
89
90 #### parse_at can be specified through sh -O
91 $SH +O parse_at -c 'words=(a "b c"); argv.py @words'
92 $SH -O parse_at -c 'words=(a "b c"); argv.py @words'
93 ## STDOUT:
94 ['@words']
95 ['a', 'b c']
96 ## END
97
98 #### @a splices into $0
99 shopt -s simple_word_eval parse_at
100 a=(echo hi)
101 "${a[@]}"
102 @a
103
104 # Bug fix
105 shopt -s strict_array
106
107 "${a[@]}"
108 @a
109 ## STDOUT:
110 hi
111 hi
112 hi
113 hi
114 ## END
115
116 #### ARGV is alias for "$@"
117 shopt -s parse_at
118 argv.py "$@"
119 argv.py @ARGV
120 argv.py "${ARGV[@]}" # not useful, but it works!
121
122 set -- 'a b' c
123 argv.py "$@"
124 argv.py @ARGV
125
126 f() {
127 argv.py "$@"
128 argv.py @ARGV
129 }
130 f 1 '2 3'
131 ## STDOUT:
132 []
133 []
134 []
135 ['a b', 'c']
136 ['a b', 'c']
137 ['1', '2 3']
138 ['1', '2 3']
139 ## END
140
141 #### shopt -s strict:all
142 shopt -s strict:all
143 # normal option names
144 shopt -o -p | grep -- ' -o ' | grep -v hashall
145 shopt -p strict:all
146 ## STDOUT:
147 set -o errexit
148 set -o nounset
149 set -o pipefail
150 shopt -s errexit
151 shopt -s inherit_errexit
152 shopt -s nounset
153 shopt -s nullglob
154 shopt -s pipefail
155 shopt -s strict_argv
156 shopt -s strict_arith
157 shopt -s strict_array
158 shopt -s strict_control_flow
159 shopt -s strict_errexit
160 shopt -s strict_glob
161 shopt -s strict_nameref
162 shopt -s strict_tilde
163 shopt -s strict_word_eval
164 ## END
165
166 #### shopt -s oil:basic
167 shopt -s oil:basic
168 # normal option names
169 shopt -o -p | grep -- ' -o ' | grep -v hashall
170 shopt -p oil:basic
171 ## STDOUT:
172 set -o errexit
173 set -o nounset
174 set -o pipefail
175 shopt -s command_sub_errexit
176 shopt -u dashglob
177 shopt -s errexit
178 shopt -u expand_aliases
179 shopt -s inherit_errexit
180 shopt -s nounset
181 shopt -s nullglob
182 shopt -s parse_at
183 shopt -s parse_brace
184 shopt -s parse_paren
185 shopt -s parse_triple_dots
186 shopt -s parse_triple_quoted
187 shopt -s pipefail
188 shopt -s process_sub_fail
189 shopt -s simple_word_eval
190 shopt -s strict_argv
191 shopt -s strict_arith
192 shopt -s strict_array
193 shopt -s strict_control_flow
194 shopt -s strict_errexit
195 shopt -s strict_glob
196 shopt -s strict_nameref
197 shopt -s strict_tilde
198 shopt -s strict_word_eval
199 ## END
200
201 #### osh -O oil:basic
202 $SH -O oil:basic -c 'var x = %(one two three); write @x'
203 ## STDOUT:
204 one
205 two
206 three
207 ## END
208
209 #### strict:all includes inherit_errexit
210 shopt -s strict:all
211 echo $(echo one; false; echo two)
212 ## STDOUT:
213 one
214 ## END
215
216 #### parse_set
217 x=init
218
219 set x=42
220 echo x=$x
221 echo argv "$@"
222
223 shopt -s parse_set
224 set x=42
225 builtin set --
226 echo x=$x
227 echo argv "$@"
228
229 ## STDOUT:
230 x=init
231 argv x=42
232 x=42
233 argv
234 ## END
235
236 #### parse_brace: bad block to assignment builtin
237 shopt -s oil:basic
238 # This is a fatal programming error. It's unlike passing an extra arg?
239 local x=y { echo 'bad block' }
240 echo status=$?
241 ## status: 1
242 ## stdout-json: ""
243
244 #### parse_brace: bad block to external program
245 shopt -s oil:basic
246 # This is a fatal programming error. It's unlike passing an extra arg?
247 ls { echo 'bad block' }
248 echo status=$?
249 ## status: 1
250 ## stdout-json: ""
251
252 #### parse_brace: cd { } in pipeline
253 shopt -s oil:basic
254 cd /tmp {
255 pwd
256 pwd
257 } | tr a-z A-Z
258 ## STDOUT:
259 /TMP
260 /TMP
261 ## END
262
263
264 #### parse_brace: if accepts blocks
265 shopt -s oil:basic
266 shopt -u errexit # don't need strict_errexit check!
267
268 if test -n foo {
269 echo one
270 }
271 # harder
272 if test -n foo; test -n bar {
273 echo two
274 }
275
276 # just like POSIX shell!
277 if test -n foo;
278
279 test -n bar {
280 echo three
281 }
282
283 if test -z foo {
284 echo if
285 } else {
286 echo else
287 }
288
289 if test -z foo {
290 echo if
291 } elif test -z '' {
292 echo elif
293 } else {
294 echo else
295 }
296
297 echo 'one line'
298 if test -z foo { echo if } elif test -z '' { echo 1 }; if test -n foo { echo 2 };
299
300 echo 'sh syntax'
301 if test -z foo; then echo if; elif test -z ''; then echo 1; fi; if test -n foo { echo 2 };
302
303 # NOTE: This is not alowed because it's like a brace group!
304 # if test -n foo; {
305
306 ## STDOUT:
307 one
308 two
309 three
310 else
311 elif
312 one line
313 1
314 2
315 sh syntax
316 1
317 2
318 ## END
319
320 #### parse_brace: brace group in if condition
321
322 # strict_errexit would make this a RUNTIME error
323 shopt -s parse_brace
324 if { echo one; echo two } {
325 echo three
326 }
327 ## STDOUT:
328 one
329 two
330 three
331 ## END
332
333 #### parse_brace: while/until
334 shopt -s oil:basic
335 while true {
336 echo one
337 break
338 }
339 while true { echo two; break }
340
341 echo 'sh syntax'
342 while true; do echo three; break; done
343 ## STDOUT:
344 one
345 two
346 sh syntax
347 three
348 ## END
349
350 #### parse_brace: for-in loop
351 shopt -s oil:basic
352 for x in one two {
353 echo $x
354 }
355 for x in three { echo $x }
356
357 echo 'sh syntax'
358 for x in four; do echo $x; done
359
360 ## STDOUT:
361 one
362 two
363 three
364 sh syntax
365 four
366 ## END
367
368 #### parse_brace case
369 shopt -s oil:basic
370
371 var files = %(foo.py 'foo test.sh')
372 for name in "${files[@]}" ; do
373 case $name in
374 *.py)
375 echo python
376 ;;
377 *.sh)
378 echo shell
379 ;;
380 esac
381 done
382
383 for name in @files {
384 case $name {
385 (*.py)
386 echo python
387 ;;
388 (*.sh) echo shell ;;
389 }
390 }
391
392 ## STDOUT:
393 python
394 shell
395 python
396 shell
397 ## END
398
399 #### parse_paren: if statement
400 shopt -s oil:basic
401 var x = 1
402 if (x < 42) {
403 echo less
404 }
405
406 if (x < 0) {
407 echo negative
408 } elif (x < 42) {
409 echo less
410 }
411
412 if (x < 0) {
413 echo negative
414 } elif (x < 1) {
415 echo less
416 } else {
417 echo other
418 }
419
420
421 ## STDOUT:
422 less
423 less
424 other
425 ## END
426
427 #### parse_paren: while statement
428 shopt -s oil:basic
429
430 # ksh style
431 var x = 1
432 while (( x < 3 )) {
433 echo $x
434 setvar x += 1
435 }
436 echo 'done ksh'
437
438 # sh style
439 var y = 1
440 while test $y -lt 3 {
441 echo $y
442 setvar y += 1
443 }
444 echo 'done sh'
445
446 # oil
447 var z = 1
448 while (z < 3) {
449 echo $z
450 setvar z += 1
451 }
452 echo 'done oil'
453
454 ## STDOUT:
455 1
456 2
457 done ksh
458 1
459 2
460 done sh
461 1
462 2
463 done oil
464 ## END
465
466 #### while subshell without parse_paren
467 while ( echo one ); do
468 echo two
469 break
470 done
471 ## STDOUT:
472 one
473 two
474 ## END
475
476 #### parse_paren: for loop
477 shopt -s oil:basic
478 var array = %(one two three)
479 for (item in array) {
480 echo $item
481 }
482
483 echo ---
484
485 declare -A A=([k]=v [k2]=v2) # iterate over keys
486 for (key in A) {
487 echo $key
488 } | sort
489 ## STDOUT:
490 one
491 two
492 three
493 ---
494 k
495 k2
496 ## END
497
498 #### parse_equals: allows bare assignment
499 shopt -s oil:all # including nice options
500 x = 1 + 2*3
501 echo $x
502 ## STDOUT:
503 7
504 ## END
505
506 #### parse_equals: disallows ENV=val mycommand
507 shopt -s oil:all
508 ENV=val echo hi
509 ## status: 2
510 ## stdout-json: ""
511
512 #### parse_equals: disallows var=val
513 shopt -s oil:all
514 var=val
515 ## status: 2
516 ## stdout-json: ""
517
518 #### parse_rawc: C strings in %() array literals
519 shopt -s oil:basic
520
521 # BUG: Surprising that this doesn't work because of command mode!
522 var lines=%(c'aa\tbb' c'cc\tdd')
523 echo @lines
524
525 ## STDOUT:
526 ## END
527
528
529 #### parse_paren allows f(x)
530 shopt -s parse_paren
531 func f(x) {
532 echo foo $x
533 }
534 f(42)
535 ## STDOUT:
536 foo 42
537 ## END
538
539 #### nullglob is on with oil:basic
540 write one *.zzz two
541 shopt -s oil:basic
542 write __
543 write one *.zzz two
544 ## STDOUT:
545 one
546 *.zzz
547 two
548 __
549 one
550 two
551 ## END
552
553 #### nullglob is on with oil:all
554 write one *.zzz two
555 shopt -s oil:all
556 write __
557 write one *.zzz two
558 ## STDOUT:
559 one
560 *.zzz
561 two
562 __
563 one
564 two
565 ## END
566
567 #### shopt -s simple_echo
568 foo='one two'
569 echo $foo # bad split then join
570 shopt -s simple_echo
571 echo
572 echo "$foo" # good
573 echo -e "$foo" # still good
574 echo $foo
575 ## status: 2
576 ## STDOUT:
577 one two
578
579 one two
580 one two
581 ## END
582
583 #### shopt -s dashglob
584 mkdir globdir
585 cd globdir
586
587 touch -- file -v
588
589 argv.py *
590
591 shopt -s oil:basic # turns OFF dashglob
592 argv.py *
593
594 shopt -s dashglob # turn it ON
595 argv.py *
596
597 ## STDOUT:
598 ['-v', 'file']
599 ['file']
600 ['-v', 'file']
601 ## END
602
603 #### shopt -s oil:basic turns some options on and others off
604 show() {
605 shopt -p | egrep 'dashglob|strict_arith'
606 }
607
608 show
609 echo ---
610
611 shopt -s strict_arith
612 show
613 echo ---
614
615 shopt -s oil:basic # strict_arith should still be on after this!
616 show
617 echo ---
618
619 shopt -u oil:basic # strict_arith should still be on after this!
620 show
621
622 ## STDOUT:
623 shopt -s dashglob
624 shopt -u strict_arith
625 ---
626 shopt -s dashglob
627 shopt -s strict_arith
628 ---
629 shopt -u dashglob
630 shopt -s strict_arith
631 ---
632 shopt -s dashglob
633 shopt -u strict_arith
634 ## END
635
636 #### oil:basic disables aliases
637
638 alias x='echo hi'
639 x
640
641 shopt --set oil:basic
642 shopt --unset errexit
643 x
644 echo status=$?
645
646 shopt --set expand_aliases
647 x
648
649 ## STDOUT:
650 hi
651 status=127
652 hi
653 ## END
654
655