1 #### benchmark.fact5.test
2 fact() {
3 n=$1
4 if [ "$n" -le 0 ]
5 then echo 1
6 else echo $((n * $(fact $(($n-1)) ) ))
7 fi
8 }
9
10 fact 5
11
12 timing=$(times | head -n 1)
13 minutes=$(echo $timing | sed 's/\([0-9]*\)m\([0-9]*\).\([0-9]*\)s.*/\1/')
14 seconds=$(echo $timing | sed 's/\([0-9]*\)m\([0-9]*\).\([0-9]*\)s.*/\2/')
15 fractional=$(echo $timing | sed 's/\([0-9]*\)m\([0-9]*\).\([0-9]*\)s.*/\3/')
16
17 echo $timing >&2
18
19 [ "$minutes" -eq 0 ] && [ "$seconds" -eq 0 ] && [ 1"$fractional" -lt 1003000 ]
20
21 ## STDOUT:
22 120
23 ## END
24
25 #### benchmark.while.test
26 x=0
27 while [ $x -lt 500 ]
28 do
29 : $((x+=1))
30 done
31 echo $x
32
33 timing=$(times | head -n 1)
34 minutes=$(echo $timing | sed 's/\([0-9]*\)m\([0-9]*\).\([0-9]*\)s.*/\1/')
35 seconds=$(echo $timing | sed 's/\([0-9]*\)m\([0-9]*\).\([0-9]*\)s.*/\2/')
36 fractional=$(echo $timing | sed 's/\([0-9]*\)m\([0-9]*\).\([0-9]*\)s.*/\3/')
37
38 if [ "$CI" ] # lolsob
39 then
40 target=002000
41 else
42 target=001000
43 fi
44
45 [ "$minutes" -eq 0 ] && [ "$seconds" -eq 0 ] && [ 1"$fractional" -lt 1"$target" ]
46
47
48 ## STDOUT:
49 500
50 ## END
51
52 #### builtin.alias.empty.test
53 set -e
54
55 alias empty=''
56 empty
57
58 ## stdout-json: ""
59
60 #### builtin.break.lexical.test
61 brk() { break 5 2>/dev/null; echo post; }
62 i=0; while [ $i -lt 5 ]; do echo $i; brk; : $((i+=1)); done
63 ## STDOUT:
64 0
65 post
66 1
67 post
68 2
69 post
70 3
71 post
72 4
73 post
74 ## END
75
76 #### builtin.break.nonlexical.test
77 set -o nonlexicalctrl 2>/dev/null
78 brk() { break 5 2>/dev/null; echo post; }
79 i=0; while [ $i -lt 5 ]; do echo $i; brk; : $((i+=1)); done
80 ## STDOUT:
81 0
82 ## END
83
84 #### builtin.cd.pwd.test
85 pwd -P # resolve physical PWD
86 orig=$(pwd)
87 echo $orig $PWD
88 [ "$orig" = "$PWD" ] || exit 1
89 mkdir inner
90 cd inner
91 [ "$orig"/inner = "$PWD" ] || exit 2
92 [ $(pwd) = "$PWD" ] || exit 3
93 cd ..
94 [ "$orig" = "$PWD" ] || exit 4
95 [ $(pwd) = "$PWD" ] || exit 5
96
97
98 #### builtin.command.ec.test
99 false
100 command -V alias >/dev/null
101 ec=$?
102 echo $ec
103 [ $ec -eq 0 ] || exit 1
104 false
105 x=$(command -V alias)
106 ec=$?
107 echo $ec
108 [ $ec -eq 0 ] || exit 2
109 command -V nonesuch >/dev/null && exit 3
110 exit 0
111 ## STDOUT:
112 0
113 0
114 ## END
115
116 #### builtin.command.exec.test
117 echo hi >file
118 command exec 8<file
119 read msg <&8
120 echo $msg
121 ## STDOUT:
122 hi
123 ## END
124
125 #### builtin.command.keyword.test
126 # ADDTOPOSIX
127 set -e
128 command -v !
129 command -v while
130 command -V while >/dev/null 2>&1
131 type do >/dev/null 2>&1
132 ## STDOUT:
133 !
134 while
135 ## END
136
137 #### builtin.command.nospecial.test
138 command readonly x=foo
139 command readonly x=bar
140 echo ?=$?
141
142 ## STDOUT:
143 ?=1
144 ## END
145
146 #### builtin.command.special.assign.test
147 unset x
148 x=whoops command :
149 echo ${x-unset}
150 ## STDOUT:
151 unset
152 ## END
153
154 #### builtin.continue.lexical.test
155 cnt() { continue 5 2>/dev/null; echo post; }
156 i=0; while [ $i -lt 5 ]; do echo $i; : $((i+=1)); cnt; echo after; done
157 ## STDOUT:
158 0
159 post
160 after
161 1
162 post
163 after
164 2
165 post
166 after
167 3
168 post
169 after
170 4
171 post
172 after
173 ## END
174
175 #### builtin.continue.nonlexical.test
176 set -o nonlexicalctrl 2>/dev/null
177 cnt() { continue 2>/dev/null; echo post; }
178 i=0; while [ $i -lt 5 ]; do echo $i; : $((i+=1)); cnt; echo after; done
179 ## STDOUT:
180 0
181 1
182 2
183 3
184 4
185 ## END
186
187 #### builtin.dot.break.test
188 echo break >scr
189 for x in a b c
190 do
191 echo $x
192 . ./scr
193 done
194 ## STDOUT:
195 a
196 b
197 c
198 ## END
199
200 #### builtin.dot.nonexistent.test
201 . ./nonesuch
202
203 ## status: 1
204 ## stdout-json: ""
205
206 #### builtin.dot.path.test
207 set -e
208
209 # manual cleanup to avoid prompt
210 mkdir p1 p2
211 trap 'rm -rf p1 p2' EXIT
212
213 cat >scr1 <<EOF
214 PATH="$(pwd)/p1:$(pwd)/p2:$PATH"
215 . scr2
216 EOF
217
218 echo 'echo nope' >p1/scr2
219 echo 'echo yep' >p2/scr2
220
221 chmod -f 333 p1/scr2
222 chmod -f 444 p2/scr2
223
224 $TEST_SHELL scr1
225
226
227 ## STDOUT:
228 yep
229 ## END
230
231 #### builtin.dot.return.test
232 cat >scr <<EOF
233 echo always
234 (exit 47)
235 return
236 echo never
237 EOF
238 . ./scr
239 [ $? -eq 47 ] || exit 1
240 echo done
241 ## STDOUT:
242 always
243 done
244 ## END
245
246 #### builtin.dot.unreadable.test
247 set -e
248
249 echo echo yes >weird
250 . ./weird
251
252 echo echo no >weird
253 chmod a-r weird
254 ! $TEST_SHELL -c '. ./weird'
255 rm -f weird
256 echo done
257 ## STDOUT:
258 yes
259 done
260 ## END
261
262 #### builtin.echo.exitcode.test
263 # Make sure that echo properly sets its exitcode.
264 echo >/dev/null && echo OK
265 echo >/dev/full || echo OK
266
267 ## STDOUT:
268 OK
269 OK
270 ## END
271
272 #### builtin.eval.break.test
273 for x in a b c; do echo $x; eval break; done
274
275 ## STDOUT:
276 a
277 ## END
278
279 #### builtin.eval.test
280 echo starting
281 eval echo hi
282 echo nice
283 eval "x=bye"
284 echo $x
285
286
287 ## STDOUT:
288 starting
289 hi
290 nice
291 bye
292 ## END
293
294 #### builtin.eval.trap.test
295 # Harald van Dijk <harald@gigawatt.nl> (2020-01-06) (inbox list)
296 # Subject: EXIT trap handling in subshells broken
297 # To: DASH shell mailing list <dash@vger.kernel.org>
298 # Date: Mon, 06 Jan 2020 21:57:20 +0000
299
300 eval '(trap "echo bug" EXIT)' >/dev/null
301 echo ok
302 ## STDOUT:
303 ok
304 ## END
305
306 #### builtin.exec.badredir.test
307 exec 9&<-
308
309 ## status: 1
310 ## stdout-json: ""
311
312 #### builtin.exec.modernish.mkfifo.loop.test
313 [ -e pipe ] && rm pipe
314 mkfifo pipe
315 ( echo hello >&8 ) 8>pipe &
316 command exec 8<pipe
317 read -r line <&8 ; echo $?
318 echo read [${line-UNSET}]
319 ## STDOUT:
320 0
321 read [hello]
322 ## END
323
324 #### builtin.exec.noargs.ec.test
325 false || command exec
326 echo ok
327
328 ## STDOUT:
329 ok
330 ## END
331
332 #### builtin.exec.true.test
333 exec true
334 false
335
336
337 #### builtin.exit0.test
338 exit 0
339
340
341 #### builtin.exitcode.test
342 # Check if builtin commands properly set their exit codes.
343
344 high_exit() {
345 return 42
346 }
347
348 # break, continue, exit, return and newgrp are not tested.
349 COMMANDS=": shift unset export readonly local times eval source exec
350 set trap true false pwd echo cd hash type command umask alias unalias
351 wait jobs read test [ printf kill getopts fg bg help history fc
352 ulimit"
353
354 # Check if every command sets the exit code for itself.
355 echo Leaking commands:
356 for command in $COMMANDS; do
357 high_exit
358 rc=$($command </dev/null >/dev/null 2>/dev/null; echo $?)
359 if [ -z $rc ]; then
360 # Skip if for some reason the subshell failed.
361 continue
362 elif [ $rc -eq 42 ]; then
363 echo $command
364 fi
365 done
366
367 # Check if any command lies about its failure.
368 echo Silently failing commands:
369 for command in $COMMANDS; do
370 has_output=$($command </dev/null 2>&1 | wc -c)
371 if [ $has_output -eq 0 ]; then
372 continue
373 fi
374 true
375 rc=$($command </dev/null >/dev/full 2>/dev/full; echo $?)
376 if [ -z $rc ]; then
377 continue
378 elif [ $rc -eq 0 ]; then
379 echo $command
380 fi
381 done
382
383 # More involved cases.
384 export FOO=1
385 readonly FOO
386 alias foo=bar
387 alias baz=qux
388 while read command; do
389 true
390 rc=$($command </dev/null >/dev/full 2>/dev/full; echo $?)
391 if [ -z $rc ]; then
392 continue
393 elif [ $rc -eq 0 ]; then
394 echo $command
395 fi
396 done <<EOF
397 export -p
398 readonly -p
399 type echo
400 command -p ''
401 command -v echo
402 command -V echo
403 alias
404 alias foo
405 alias foo baz
406 alias bar
407 printf "foo"
408 kill -l
409 kill -l 1
410 kill -l 2 3
411 help builtins
412 help version
413 help trace
414 help spec
415 EOF
416
417 ## STDOUT:
418 Leaking commands:
419 Silently failing commands:
420 ## END
421
422 #### builtin.export.override.test
423 unset x
424 $TEST_UTIL/getenv x
425 x=4
426 $TEST_UTIL/getenv x
427 export x=5
428 $TEST_UTIL/getenv x
429 x=6 $TEST_UTIL/getenv x
430 echo x is ${x-unset}
431
432 ## STDOUT:
433 x is unset
434 x is unset
435 x='5'
436 x='6'
437 x is 5
438 ## END
439
440 #### builtin.export.test
441 cat >scr <<'EOF'
442 echo ${var-unset}
443 EOF
444 $TEST_SHELL scr
445 var=hi
446 $TEST_SHELL scr
447 var=here $TEST_SHELL scr
448 export var=bye
449 $TEST_SHELL scr
450
451 ## STDOUT:
452 unset
453 unset
454 here
455 bye
456 ## END
457
458 #### builtin.export.unset.test
459 set -e
460 unset x
461 export x
462 export -p | grep 'export x'
463 echo ok
464 ## STDOUT:
465 export x
466 ok
467 ## END
468
469 #### builtin.falsetrue.test
470 false || true
471
472
473 #### builtin.hash.nonposix.test
474 ls >/dev/null
475 hash | grep ls >/dev/null || exit 1
476 touch hi
477 hash | grep ls >/dev/null || exit 2
478 hash | grep touch >/dev/null || exit 3
479 hash -r
480 hash | grep ls >/dev/null && exit 4
481 hash | grep touch >/dev/null && exit 5
482 echo ok
483 ## STDOUT:
484 ok
485 ## END
486
487 #### builtin.jobs.test
488 sleep 10 & pid=$!
489 sleep 1
490 jobs >job_info
491 grep "sleep 10" job_info >/dev/null || exit 1
492 grep "[1]" job_info >/dev/null || exit 2
493 kill $pid
494
495 rm job_info
496 unset j pid
497
498 sleep 10 & pid=$!
499 sleep 1
500 jobs -l >job_info
501 grep "sleep 10" job_info >/dev/null || exit 3
502 grep "[1]" job_info >/dev/null || exit 4
503 grep $pid job_info >/dev/null || exit 5
504 kill $pid
505
506 rm job_info
507 ## stdout-json: ""
508
509 #### builtin.kill0_+5.test
510 ! kill -s 0 $(($$+5))
511
512
513 #### builtin.kill0.test
514 kill -s 0 $$
515
516
517 #### builtin.kill.jobs.test
518 sleep 5 & pid1=$!
519 sleep 6 & pid2=$!
520 start=$(date "+%s")
521 sleep 1
522 kill %1 %2 && exit 3
523 kill $pid1 $pid2
524 wait
525 stop=$(date "+%s")
526 elapsed=$((stop - start))
527 echo $stop - $start = $elapsed
528 [ $((elapsed)) -lt 3 ] || exit 1
529
530 echo setting -m
531 set -m
532 echo sleeping
533 jobs -l
534 sleep 5 & pid1=$!
535 sleep 6 & pid2=$!
536 start=$(date "+%s")
537 sleep 1
538 jobs -l
539 kill %1 %2
540 wait
541 stop=$(date "+%s")
542 elapsed=$((stop - start))
543 echo $stop - $start = $elapsed
544 [ $((elapsed)) -lt 3 ] || exit 2
545
546
547 #### builtin.kill.signame.test
548 rm -f foo
549 set -e
550
551 trap 'touch foo' TERM
552
553 kill $$
554 [ -f foo ] && ! [ -s foo ]
555 rm foo
556 echo plain kill
557
558 kill -TERM $$
559 [ -f foo ] && ! [ -s foo ]
560 rm foo
561 echo named \(-TERM\)
562
563 kill -15 $$
564 [ -f foo ] && ! [ -s foo ]
565 rm foo
566 echo numbered \(-15\)
567
568 ## STDOUT:
569 plain kill
570 named (-TERM)
571 numbered (-15)
572 ## END
573
574 #### builtin.printf.repeat.test
575 printf '%d %d\n' 1 2 3 4 5 6 7 8 9
576 ## STDOUT:
577 1 2
578 3 4
579 5 6
580 7 8
581 9 0
582 ## END
583
584 #### builtin.pwd.exitcode.test
585 # Make sure that pwd sets its exitcode.
586 false
587 pwd >/dev/null 2>/dev/null && echo OK
588
589 ## STDOUT:
590 OK
591 ## END
592
593 #### builtin.readonly.assign.noninteractive.test
594 readonly a=b
595 export a=c
596 echo egad
597
598 ## status: 1
599 ## stdout-json: ""
600
601 #### builtin.set.-m.test
602 set -m
603 echo hi
604
605 ## STDOUT:
606 hi
607 ## END
608
609 #### builtin.set.quoted.test
610 myvar='a b c'
611 set | grep myvar >scr
612 . ./scr
613 printf '%s\n' $myvar
614
615 ## STDOUT:
616 a
617 b
618 c
619 ## END
620
621 #### builtin.source.nonexistent.earlyexit.test
622 source not_a_thing
623 echo hi
624 exit 0
625 ## status: 1
626 ## stdout-json: ""
627
628 #### builtin.source.nonexistent.test
629 source nonesuch
630 . nonesuch
631
632 ## status: 1
633 ## stdout-json: ""
634
635 #### builtin.source.setvar.test
636 set -e
637
638 echo 'x=5' >to_source
639 source ./to_source
640 echo ${x?:unset}
641 rm to_source
642 [ "$x" -eq 5 ]
643 ## STDOUT:
644 5
645 ## END
646
647 #### builtin.special.redir.error.test
648 : 2>&9
649 echo oh no
650
651 ## status: 1
652 ## stdout-json: ""
653
654 #### builtin.test.bigint.test
655 ! test -t 12323454234578326584376438
656 echo ok
657 ## STDOUT:
658 ok
659 ## END
660
661 #### builtin.test.nonposix.test
662 touch first
663 [ first -ef first ] || exit 3
664 sleep 1
665 touch second
666 [ second -nt first ] || exit 3
667 [ second -ot first ] && exit 4
668 [ first -ot second ] || exit 5
669 [ first -nt second ] && exit 6
670 mkdir up
671 [ first -ef up/../first ] || exit 7
672 [ first -ef up/../up/../second ] && exit 8
673 exit 0
674
675
676 #### builtin.test.-nt.-ot.absent.test
677 touch present
678 [ present -nt absent ] || exit 1
679 [ absent -ot present ] || exit 2
680
681
682 #### builtin.test.numeric.spaces.nonposix.test
683 test " 5" -eq " 5 "
684
685
686 #### builtin.test.symlink.test
687 echo hi >file
688 mkdir dir
689 ln -s file link_file
690 ln -s dir link_dir
691 [ -e file ] && [ -e link_file ] && \
692 [ -f file ] && [ -f link_file ] && \
693 [ -e dir ] && [ -e link_dir ] && \
694 [ -d dir ] && [ -d link_dir ] && \
695 [ -L link_file ] && [ -L link_dir ]
696
697 #### builtin.times.ioerror.test
698 exec 3>&1
699 (
700 trap "" PIPE
701 sleep 1
702 command times
703 echo ?=$? >&3
704 ) | true
705
706 ## STDOUT:
707 ?=2
708 ## END
709
710 #### builtin.trap.chained.test
711 # https://www.spinics.net/lists/dash/msg01771.html
712 trap exit INT
713 trap 'true; kill -s INT $$' EXIT
714 false
715
716
717 #### builtin.trap.exit3.test
718 # https://www.spinics.net/lists/dash/msg01750.html
719 trap '(exit 3) && echo BUG' INT
720 kill -s INT $$
721
722 ## stdout-json: ""
723
724 #### builtin.trap.exitcode.test
725 # https://www.spinics.net/lists/dash/msg01770.html
726
727 trap 'set -o bad@option' INT
728 kill -s INT $$
729
730
731 #### builtin.trap.exit.subshell.test
732 trap 'echo bye' EXIT
733 (echo hi)
734 echo $(echo hi)
735
736 ## STDOUT:
737 hi
738 hi
739 bye
740 ## END
741
742 #### builtin.trap.false.test
743 # https://www.spinics.net/lists/dash/msg01750.html
744 trap '(false) && echo BUG' INT
745 kill -s INT $$
746
747 ## stdout-json: ""
748
749 #### builtin.trap.kill.undef.test
750 trap 'echo derp' KILL
751 trap 'echo nevah' 9
752
753 ## stdout-json: ""
754
755 #### builtin.trap.nested.test
756 # https://www.spinics.net/lists/dash/msg01762.html
757 trap '(trap "echo exit" EXIT; :)' EXIT
758 ## STDOUT:
759 exit
760 ## END
761
762 #### builtin.trap.noexit.test
763 trap - 55
764 echo hi
765
766 ## STDOUT:
767 hi
768 ## END
769
770 #### builtin.trap.redirect.test
771 # Harald van Dijk <harald@gigawatt.nl> (2020-01-06) (list)
772 # Subject: EXIT trap handling in subshells broken
773 # To: DASH shell mailing list <dash@vger.kernel.org>
774 # Date: Mon, 06 Jan 2020 21:57:20 +0000
775
776 f() { (trap "echo $var" EXIT); }
777 var=bad
778 var=ok f
779
780 ## STDOUT:
781 ok
782 ## END
783
784 #### builtin.trap.return.test
785 # https://www.spinics.net/lists/dash/msg01792.html
786 trap 'f() { false; return; }; f; echo $?' EXIT
787 ## STDOUT:
788 1
789 ## END
790
791 #### builtin.trap.subshell.false.exit.test
792 trap "(false) && echo BUG" EXIT
793
794 ## status: 1
795 ## stdout-json: ""
796
797 #### builtin.trap.subshell.false.test
798 trap "(false) && echo BUG" INT; kill -s INT $$
799
800 ## stdout-json: ""
801
802 #### builtin.trap.subshell.loud2.test
803 # https://www.spinics.net/lists/dash/msg01766.html
804 trap 'set -o bad@option' INT; kill -s INT $$ && echo HUH
805 trap '(:; exit) && echo WEIRD' EXIT; false
806 ## STDOUT:
807 HUH
808 WEIRD
809 ## END
810
811 #### builtin.trap.subshell.loud.test
812 # https://www.spinics.net/lists/dash/msg01766.html
813 trap '(:; exit) && echo WEIRD' EXIT; false
814 ## STDOUT:
815 WEIRD
816 ## END
817
818 #### builtin.trap.subshell.quiet.test
819 # https://www.spinics.net/lists/dash/msg01755.html
820 (trap '(! :) && echo BUG1' EXIT)
821 (trap '(false) && echo BUG2' EXIT)
822 (trap 'readonly foo=bar; (foo=baz) && echo BUG3' EXIT)
823 (trap '(set -o bad@option) && echo BUG4' EXIT)
824 exit 0
825 ## stdout-json: ""
826
827 #### builtin.trap.subshell.true.ec1.test
828 # https://www.spinics.net/lists/dash/msg01761.html
829 trap '(true) || echo bug' EXIT; false
830
831 ## stdout-json: ""
832
833 #### builtin.trap.subshell.truefalse.test
834 # https://www.spinics.net/lists/dash/msg01750.html
835 trap '(false) && echo BUG' INT; kill -s INT $$
836 trap "(false) && echo BUG" EXIT
837 trap "(false); echo \$?" EXIT
838
839 ## STDOUT:
840 1
841 ## END
842
843 #### builtin.trap.supershell.test
844 trap 'echo bye' EXIT
845 (trap)
846 (trap 'echo so long' EXIT; trap)
847 (trap)
848
849 ## STDOUT:
850 trap -- 'echo bye' EXIT
851 trap -- 'echo so long' EXIT
852 so long
853 trap -- 'echo bye' EXIT
854 bye
855 ## END
856
857 #### builtin.unset.test
858 readonly x=foo
859 y=bar
860 unset y
861 echo ${y-unset}
862 echo ${x-error}
863 unset y
864 echo ${y-unset}
865 unset x
866
867 ## status: 1
868 ## STDOUT:
869 unset
870 foo
871 unset
872 ## END
873
874 #### parse.emptyvar.test
875 err=$($TEST_SHELL -c ': ${}' 2>&1 >/dev/null)
876 [ "$err" ]
877
878
879
880
881 #### parse.eval.error.test
882 cat >scr <<EOF
883 eval "if"
884 echo lived
885 EOF
886 $TEST_SHELL scr && exit 1
887 exit 0
888 ## stdout-json: ""
889
890 #### semantics.arith.assign.multi.test
891 : $((x = y = z = 0))
892 echo $x $y $z
893 ## STDOUT:
894 0 0 0
895 ## END
896
897 #### semantics.arithmetic.bool_to_num.test
898 [ $((5>=5)) -eq 1 ]
899
900
901 #### semantics.arithmetic.tilde.test
902 # bug found in POSIX testing (sh_05.ex tp357)
903
904 echo $((~10))
905 ## STDOUT:
906 -11
907 ## END
908
909 #### semantics.arith.modernish.test
910 # from https://github.com/modernish/modernish/blob/e3b66a8b68695265b9aebd43e1de1ab3fef66e57/lib/modernish/aux/fatal.sh
911 i=7
912 j=0
913 case $(( ((j+=6*i)==0x2A)>0 ? 014 : 015 )) in
914 ( 12 | 14 ) echo ok;; # OK or BUG_NOOCTAL
915 ( * ) echo fail; exit 1 ;;
916 esac
917 case $j in
918 ( 42 ) echo ok;; # BUG_NOOCTAL
919 ( * ) echo fail; exit 1;;
920 esac
921
922 ## STDOUT:
923 ok
924 ok
925 ## END
926
927 #### semantics.arith.pos.test
928 a=+47
929 [ $((a)) -eq 47 ]
930 echo $((a))
931 ## STDOUT:
932 47
933 ## END
934
935 #### semantics.arith.var.space.test
936 x=" 8"
937 y=$((x + 1))
938 echo $x $y
939
940 ## STDOUT:
941 8 9
942 ## END
943
944 #### semantics.assign.noglob.test
945 x='*'
946 echo "$x"
947
948 ## STDOUT:
949 *
950 ## END
951
952 #### semantics.assign.visible.test
953 set -e
954 x=5 y=$((x+2))
955 [ "$x" -eq 5 ]
956 # either x is treated as unset (and so y = 2) or not (and so y = 7)
957 [ "$y" -eq 2 ] || [ "$y" -eq 7 ]
958 echo ok
959 ## STDOUT:
960 ok
961 ## END
962
963 #### semantics.background.nojobs.stdin.test
964 cat >scr <<EOF
965 set +m
966 exec <in
967 cat &
968 wait
969 EOF
970
971 echo illegible >in
972 $TEST_SHELL scr
973
974
975 #### semantics.background.pid.test
976 echo 'echo $$ > pid.out' >showpid.sh
977 chmod +x showpid.sh
978 $TEST_SHELL showpid.sh &
979 sleep 1
980 [ "$!" -eq "$(cat pid.out)" ]
981
982 #### semantics.background.pipe.pid.test
983 echo 'echo $$ > pid.out' >showpid.sh
984 chmod +x showpid.sh
985 true | $TEST_SHELL showpid.sh &
986 sleep 1
987 [ "$!" -eq "$(cat pid.out)" ]
988
989 #### semantics.background.test
990 echo hi
991 { sleep 1 ; echo derp ; } &
992 echo bye
993 wait
994 ## STDOUT:
995 hi
996 bye
997 derp
998 ## END
999
1000 #### semantics.backtick.exit.test
1001 foo=$(trap 'echo bar' EXIT)
1002 echo $foo >&2
1003
1004 ## stdout-json: ""
1005
1006 #### semantics.backtick.fds.test
1007 set -e
1008 subshfds=$($TEST_UTIL/fds 0 20)
1009 $TEST_UTIL/fds 0 20
1010 echo $subshfds
1011
1012 ## STDOUT:
1013 0 open
1014 1 open
1015 2 open
1016 3 closed
1017 4 closed
1018 5 closed
1019 6 closed
1020 7 closed
1021 8 closed
1022 9 closed
1023 10 closed
1024 11 closed
1025 12 closed
1026 13 closed
1027 14 closed
1028 15 closed
1029 16 closed
1030 17 closed
1031 18 closed
1032 19 closed
1033 20 closed
1034 0 open 1 open 2 open 3 closed 4 closed 5 closed 6 closed 7 closed 8 closed 9 closed 10 closed 11 closed 12 closed 13 closed 14 closed 15 closed 16 closed 17 closed 18 closed 19 closed 20 closed
1035 ## END
1036
1037 #### semantics.backtick.ppid.test
1038 set -e
1039
1040 pid1=$($TEST_SHELL -c 'echo $PPID')
1041 echo $pid1 >pid1
1042
1043 $TEST_SHELL -c 'echo $PPID' >pid2
1044
1045 [ $(cat pid1) = $(cat pid2) ] || exit 2
1046 echo pid1=pid2
1047
1048 (echo $PPID) >ppid
1049 [ $PPID = $(cat ppid) ] || exit 3
1050 echo ppid=subshell
1051 ## STDOUT:
1052 pid1=pid2
1053 ppid=subshell
1054 ## END
1055
1056 #### semantics.case.ec.test
1057 # ADDTOPOSIX
1058
1059 (exit 3)
1060 echo $? # make sure we're making good ecs
1061 case a in
1062 ( b ) (exit 4) ;;
1063 ( * ) ;; # don't alter ec
1064 esac
1065 echo $? # should be 3
1066
1067 (exit 5)
1068 case a$(echo $?>ec) in # observe ec before entering case
1069 ( b ) (exit 6) ;;
1070 esac
1071 echo $?
1072 [ $(cat ec) = "5" ] || exit 2 # shouldn't have been altered yet!
1073
1074 # make sure the ec is actually visible
1075 false
1076 case a in
1077 ( a ) echo visible $? ;;
1078 esac
1079
1080 # but make sure that no match cases set the ec to 0
1081 false
1082 case a in
1083 ( b ) (exit 6) ;;
1084 esac
1085 echo $?
1086
1087
1088 ## STDOUT:
1089 3
1090 0
1091 0
1092 visible 1
1093 0
1094 ## END
1095
1096 #### semantics.case.escape.modernish.test
1097 # from https://github.com/modernish/modernish/blob/e3b66a8b68695265b9aebd43e1de1ab3fef66e57/lib/modernish/aux/fatal.sh
1098 case 'foo\
1099 bar' in
1100 ( foo\\"
1101 "bar ) echo good ;;
1102 ( * ) echo bad ;;
1103 esac
1104
1105 ## STDOUT:
1106 good
1107 ## END
1108
1109 #### semantics.case.escape.quotes.test
1110 foo=\"
1111 echo -n Literal: ''
1112 case "$foo" in
1113 \" ) echo OK ;;
1114 * ) echo NOT OK ;;
1115 esac
1116 echo -n Unquoted: ''
1117 case "$foo" in
1118 $foo ) echo OK ;;
1119 * ) echo NOT OK ;;
1120 esac
1121 echo -n Quoted: ''
1122 case "$foo" in
1123 "$foo" ) echo OK ;;
1124 * ) echo NOT OK ;;
1125 esac
1126
1127 ## STDOUT:
1128 Literal: OK
1129 Unquoted: OK
1130 Quoted: OK
1131 ## END
1132
1133 #### semantics.command.argv0.test
1134 set -e
1135
1136 explicit=$(${TEST_UTIL}/argv)
1137 [ "$explicit" = "argv[0] = \"${TEST_UTIL}/argv\";" ]
1138
1139 PATH="${TEST_UTIL}:$PATH"
1140 inpath=$(argv)
1141 [ "$inpath" = "argv[0] = \"argv\";" ]
1142 argv
1143
1144
1145 ## STDOUT:
1146 argv[0] = "argv";
1147 ## END
1148
1149 #### semantics.command-subst.newline.test
1150 # https://www.spinics.net/lists/dash/msg01844.html
1151 cat <<END
1152 1
1153 $(echo "")
1154 2
1155 END
1156 ## STDOUT:
1157 1
1158
1159 2
1160 ## END
1161
1162 #### semantics.command-subst.test
1163 x=$(false)
1164
1165 ## status: 1
1166
1167 #### semantics.-C.test
1168 echo >in <<EOF
1169 a one
1170 a two
1171 a one two three
1172 four
1173 EOF
1174
1175 touch out
1176
1177 set -o noclobber
1178 cat <in >out
1179 [ $? -gt 0 ] || exit 2
1180
1181 #### semantics.defun.ec.test
1182 # ADDTOPOSIX
1183 false
1184 f() { echo hi ; }
1185 echo $?
1186 f
1187
1188 false
1189 f() { echo hello ; }
1190 echo $?
1191 f
1192 ## STDOUT:
1193 0
1194 hi
1195 0
1196 hello
1197 ## END
1198
1199 #### semantics.dot.glob.test
1200 has_dot() {
1201 $TEST_UTIL/readdir | grep -e '^.$' >/dev/null
1202 }
1203
1204 has_dotdot() {
1205 $TEST_UTIL/readdir | grep -e '^..$' >/dev/null
1206 }
1207
1208 mkdir -p bar/inner
1209 touch bar/foo
1210 touch bar/inner/foo
1211 cd bar/inner
1212 echo .*/foo | sort # should be ../foo and ./foo
1213
1214 # some FS may be weird and not give these entries... simulate!
1215 has_dot || echo "./foo"
1216 has_dotdot || echo "../foo"
1217
1218 cd ../../
1219 rm -r bar
1220
1221 # this issue is under active discussion on the POSIX mailing list
1222
1223 # bash, dash, yash all work
1224 # fish, zsh fail
1225 ## STDOUT:
1226 ../foo ./foo
1227 ## END
1228
1229 #### semantics.errexit.carryover.test
1230 set -e
1231 putsn() { echo "$@"; }
1232 false && true
1233 putsn "It should be executed"
1234 false && true
1235 /bin/echo hello
1236
1237 ## STDOUT:
1238 It should be executed
1239 hello
1240 ## END
1241
1242 #### semantics.errexit.subshell.test
1243 set -o errexit
1244 if ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4 ); then
1245 echo 5;
1246 fi
1247 echo 6 # This is executed because the subshell just returns false
1248 false
1249 echo 7
1250
1251 ## status: 1
1252 ## STDOUT:
1253 1
1254 2
1255 3
1256 4
1257 5
1258 6
1259 ## END
1260
1261 #### semantics.errexit.trap.test
1262 set -e; trap "false; echo BUG" USR1; kill -s USR1 $$
1263
1264 ## status: 1
1265
1266 #### semantics.error.noninteractive.test
1267 cat <<EOF > script
1268 unset x
1269 y=z
1270 echo ${x?z}
1271 echo blargh
1272 EOF
1273 chmod +x script
1274 $TEST_SHELL script
1275
1276 ## status: 1
1277
1278 #### semantics.escaping.backslash.modernish.test
1279 # from https://github.com/modernish/modernish/blob/e3b66a8b68695265b9aebd43e1de1ab3fef66e57/lib/modernish/aux/fatal.sh
1280 t=' :: \on\e :\tw'\''o \th\'\''re\e :\\'\''fo\u\r: : : '
1281 IFS=': '
1282 set -- ${t}
1283 IFS=''
1284 t=${#},${1-U},${2-U},${3-U},${4-U},${5-U},${6-U},${7-U},${8-U},${9-U},${10-U},${11-U},${12-U}
1285 case ${t} in
1286 ( '8,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,U,U,U,U' \
1287 | '9,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,,U,U,U' ) # QRK_IFSFINAL
1288 echo good ;;
1289 '8,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,U,U,U,U') echo weird;;
1290 ( * ) echo bad ; exit 1 ;;
1291 esac
1292
1293 ## STDOUT:
1294 good
1295 ## END
1296
1297 #### semantics.escaping.backslash.test
1298 printf '%s\t\n' > scr \
1299 'printf %s\\n foobar\|\&\;\<\>\(\)\$\`\\\"\'\''\ \?\*\[\'
1300 $TEST_SHELL scr
1301
1302
1303 ## STDOUT:
1304 foobar|&;<>()$`\"' ?*[
1305 ## END
1306
1307 #### semantics.escaping.heredoc.dollar.test
1308 cat <<EOF
1309 echo \\\$var
1310 EOF
1311 cat <<'EOF'
1312 echo \\\$var
1313 EOF
1314
1315 ## STDOUT:
1316 echo \$var
1317 echo \\\$var
1318 ## END
1319
1320 #### semantics.escaping.newline.test
1321 printf '%s' '\\'n
1322 printf '%s' "\n"
1323 printf "\n"
1324 printf '\n'
1325 printf '\\n'
1326
1327 ## stdout-json: "\\\\n\\n\n\n\\n"
1328
1329 #### semantics.escaping.quote.test
1330 set -e
1331
1332 for c in '"' '#' '%' '&' "'" '(' ')' '*' '+' ',' '-' '.' '/' ':' \
1333 ';' '<' '=' '>' '?' '@' '[' ']' '^' '_' '{' '|' '}' '~' ' '
1334 do
1335 cat >script <<EOF
1336 x=\`printf '%s' \\$c\`; printf '%s\\n' "\$x"
1337 EOF
1338 echo "$c"
1339 $TEST_SHELL script >out
1340 [ $? -eq 0 ] && [ "$c" = "$(cat out)" ]
1341 done
1342 echo done
1343 ## STDOUT:
1344 "
1345 #
1346 %
1347 &
1348 '
1349 (
1350 )
1351 *
1352 +
1353 ,
1354 -
1355 .
1356 /
1357 :
1358 ;
1359 <
1360 =
1361 >
1362 ?
1363 @
1364 [
1365 ]
1366 ^
1367 _
1368 {
1369 |
1370 }
1371 ~
1372
1373 done
1374 ## END
1375
1376 #### semantics.escaping.single.test
1377 # cf tp399
1378 cat <<weirdo
1379 line one
1380 line two
1381 "line".\${PATH}.\'three\'\\x\
1382 line four
1383 weirdo
1384
1385 ## STDOUT:
1386 line one
1387 line two
1388 "line".${PATH}.\'three\'\xline four
1389 ## END
1390
1391 #### semantics.eval.makeadder.test
1392 makeadder() {
1393 eval "adder() { echo \$((\$1 + $1)) ; }"
1394 }
1395
1396 makeadder 5
1397 adder 1
1398 makeadder 10
1399 adder 1
1400
1401 ## STDOUT:
1402 6
1403 11
1404 ## END
1405
1406 #### semantics.evalorder.fun.test
1407 # bash: assign
1408 # yash, dash, smoosh: redir
1409 # ADDTOPOSIX
1410 show() { echo "got ${EFF-unset}"; }
1411 unset x
1412 EFF=${x=assign} show 2>${x=redir}
1413 echo ${EFF-unset after function call}
1414 [ -f assign ] && echo assign exists && rm assign
1415 [ -f redir ] && echo redir exists && rm redir
1416
1417 ## STDOUT:
1418 got redir
1419 unset after function call
1420 redir exists
1421 ## END
1422
1423 #### semantics.expansion.heredoc.backslash.test
1424 cat <<EOF
1425 an escaped \\[bracket]
1426 should \\ work just fine
1427 EOF
1428 cat <<EOF
1429 exit \$?
1430 EOF
1431 ## STDOUT:
1432 an escaped \[bracket]
1433 should \ work just fine
1434 exit $?
1435 ## END
1436
1437 #### semantics.expansion.quotes.adjacent.test
1438 mkdir a
1439 touch a/b
1440 touch a/c
1441 echo a/*
1442 echo "a"/*
1443 echo 'a'/*
1444 mkdir "foo*["
1445 touch "foo*["/weird
1446 touch "foo*["/wild
1447 touch "foo*["/crazy
1448 echo "foo*["/*
1449 echo "foo*["/[wz]*
1450 ## STDOUT:
1451 a/b a/c
1452 a/b a/c
1453 a/b a/c
1454 foo*[/crazy foo*[/weird foo*[/wild
1455 foo*[/weird foo*[/wild
1456 ## END
1457
1458 #### semantics.expansion.substring.test
1459 FOO="\\a"
1460 echo ${FOO#*\\}
1461
1462 ## STDOUT:
1463 a
1464 ## END
1465
1466 #### semantics.for.readonly.test
1467 # ADDTOPOSIX
1468 (for x in a b c; do echo $x; readonly x; done) && exit 1
1469 exit 0
1470
1471 ## STDOUT:
1472 a
1473 ## END
1474
1475 #### semantics.fun.error.restore.test
1476 set -u
1477
1478 f() {
1479 echo $1
1480 echo <none
1481 }
1482
1483 set -- a b c
1484 f arg1 arg2
1485 printf '<%s>\n' "$@"
1486
1487 ## STDOUT:
1488 arg1
1489 <a>
1490 <b>
1491 <c>
1492 ## END
1493
1494 #### semantics.-h.nonposix.test
1495 set -h
1496 hash -r
1497 f() {
1498 ls
1499 touch hi
1500 rm hi
1501 }
1502 hash
1503 hash | grep ls || exit 1
1504 hash | grep touch || exit 2
1505 hash | grep rm || exit 3
1506
1507
1508
1509 #### semantics.ifs.combine.ws.test
1510 unset IFS
1511 echo > spaced
1512 printf "%b" '\tx' >> spaced
1513 echo >> spaced
1514 echo " 5" >> spaced
1515 printf '%b' ' 12\t ' >> spaced
1516 echo `cat spaced`
1517 IFS=$(printf '%b' ' \n\t')
1518 echo `cat spaced`
1519 ## STDOUT:
1520 x 5 12
1521 x 5 12
1522 ## END
1523
1524 #### semantics.kill.traps.test
1525 trap "echo hi" TERM
1526 sleep 10 &
1527 pid=$!
1528 sleep 1
1529 kill $pid
1530 [ "$?" -eq 0 ] || exit 1
1531 sleep 1
1532 wait $pid
1533 [ "$?" -ge 128 ] || exit 2
1534
1535
1536 ## stdout-json: ""
1537
1538 #### semantics.length.test
1539 # https://www.spinics.net/lists/dash/msg01749.html
1540 v=abc; echo ab${#v}cd
1541
1542 ## STDOUT:
1543 ab3cd
1544 ## END
1545
1546 #### semantics.monitoring.ttou.test
1547 # id:20201221162442.GA26001@stack.nl
1548 # Jilles Tjoelker <jilles@stack.nl> (2020-12-21) (list)
1549 # Subject: Re: dash 0.5.11.2, busybox sh 1.32.0, FreeBSD 12.2 sh: spring TTOU but should not i think
1550 # To: Harald van Dijk <harald@gigawatt.nl>
1551 # Cc: Steffen Nurpmeso <steffen@sdaoden.eu>, DASH shell mailing list <dash@vger.kernel.org>, Denys Vlasenko <vda.linux@googlemail.com>
1552 # Date: Mon, 21 Dec 2020 17:24:42 +0100
1553
1554 $TEST_SHELL -c "( $TEST_SHELL -c 'trap echo\ TTOU TTOU; set -m; echo all good' )"
1555
1556 ## STDOUT:
1557 all good
1558 ## END
1559
1560 #### semantics.no-command-subst.test
1561 false ; x=hi
1562
1563
1564 #### semantics.noninteractive.expansion.exit.test
1565 unset x
1566 echo ${x?alas, poor yorick}
1567
1568 ## status: 1
1569
1570 #### semantics.pattern.bracket.quoted.test
1571 # from https://github.com/modernish/modernish/blob/e3b66a8b68695265b9aebd43e1de1ab3fef66e57/lib/modernish/aux/fatal.sh
1572 t='ab]cd'
1573 case c in
1574 ( *["${t}"]* )
1575 case e in
1576 ( *[!"${t}"]* ) echo OK;;
1577 ( * ) echo FAILED inner ;;
1578 esac ;;
1579 ( * ) echo FAILED outer ;;
1580 esac
1581
1582 case \" in
1583 ( *["${t}"]* ) echo QUOTED ;;
1584 ( * ) echo UNQUOTED ;;
1585 esac
1586
1587 ## STDOUT:
1588 OK
1589 UNQUOTED
1590 ## END
1591
1592 #### semantics.pattern.hyphen.test
1593 touch file-
1594 touch filea
1595
1596 echo file[-123]
1597 echo file[123-]
1598 echo file[[.-.]]
1599 echo file[[=-=]]
1600 echo file[!-123]
1601 echo file[[:alpha:]]
1602 echo file[a-z]
1603 ## STDOUT:
1604 file-
1605 file-
1606 file-
1607 file-
1608 filea
1609 filea
1610 filea
1611 ## END
1612
1613 #### semantics.pattern.modernish.test
1614 # from https://github.com/modernish/modernish/blob/e3b66a8b68695265b9aebd43e1de1ab3fef66e57/lib/modernish/aux/fatal.sh
1615 t=' :: \on\e :\tw'\''o \th\'\''re\e :\\'\''fo\u\r: : : '
1616 IFS=': '
1617 set -- ${t}
1618 IFS=''
1619 t=${#},${1-U},${2-U},${3-U},${4-U},${5-U},${6-U},${7-U},${8-U},${9-U},${10-U},${11-U},${12-U}
1620 printf "%s\n" "$t"
1621 case ${t} in
1622 ( '8,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,U,U,U,U' \
1623 | '9,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,,U,U,U' ) # QRK_IFSFINAL
1624 echo good ;;
1625 '8,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,U,U,U,U') echo weird;;
1626 ( * ) echo bad ; exit 1 ;;
1627 esac
1628
1629
1630 #### semantics.pattern.rightbracket.test
1631 touch file]
1632 touch filea
1633
1634 echo file[]123]
1635 echo file[[.].]]
1636 echo file[[=]=]]
1637 echo file[!]123]
1638 echo file[[:alpha:]]
1639 echo file[a-z]
1640 ## STDOUT:
1641 file]
1642 file]
1643 file]
1644 filea
1645 filea
1646 filea
1647 ## END
1648
1649 #### semantics.pipe.chained.test
1650 c="echo works"
1651 for n in $(seq 1 10)
1652 do
1653 c="$c | { read x; echo \$x; }"
1654 done
1655
1656 eval $c 2>err
1657 [ -e err ] && ! [ -s err ] || exit 2
1658
1659 ## STDOUT:
1660 works
1661 ## END
1662
1663 #### semantics.quote.backslash.test
1664 echo []
1665 echo '\[]'
1666 echo "\[]"
1667
1668 ## STDOUT:
1669 []
1670 \[]
1671 \[]
1672 ## END
1673
1674 #### semantics.quote.tilde.test
1675 echo "~"
1676 ## STDOUT:
1677 ~
1678 ## END
1679
1680 #### semantics.redir.close.test
1681 # https://www.spinics.net/lists/dash/msg01775.html
1682 { exec 8</dev/null; } 8<&-; : <&8 && echo "oops, still open"
1683
1684 ## status: 1
1685 ## stdout-json: ""
1686
1687 #### semantics.redir.fds.test
1688 $TEST_UTIL/fds
1689 exec 3>&1
1690 $TEST_UTIL/fds
1691
1692 ## STDOUT:
1693 0 open
1694 1 open
1695 2 open
1696 3 closed
1697 4 closed
1698 5 closed
1699 6 closed
1700 7 closed
1701 8 closed
1702 9 closed
1703 0 open
1704 1 open
1705 2 open
1706 3 open
1707 4 closed
1708 5 closed
1709 6 closed
1710 7 closed
1711 8 closed
1712 9 closed
1713 ## END
1714
1715 #### semantics.redir.from.test
1716 set -e
1717 echo hi >file
1718 [ -s file ]
1719 read x <file
1720 [ "$x" = "hi" ]
1721 rm file
1722
1723 #### semantics.redir.indirect.test
1724 f() {
1725 echo message >&2
1726 }
1727
1728 msg=$(f 2>&1)
1729 [ "$msg" = "message" ] || exit 1
1730
1731 unset msg
1732 x=1
1733 msg=$(f 2>&$x)
1734 [ "$msg" = "message" ] || exit 2
1735
1736 echo ok
1737 ## STDOUT:
1738 ok
1739 ## END
1740
1741 #### semantics.redir.nonregular.test
1742 set -C
1743 : >/dev/null || exit 2
1744 echo ok
1745
1746 ## STDOUT:
1747 ok
1748 ## END
1749
1750 #### semantics.redir.toomany.test
1751 c="echo hi"
1752 for n in $(seq 3 10)
1753 do
1754 c="{ $c; echo hi; } >file_$n"
1755 done
1756
1757 eval $c 2>err
1758 [ -e err ] && ! [ -s err ] || exit 2
1759
1760 rm file_* err
1761
1762 MAX=$(ulimit >/dev/null 2>&1 && ulimit -n 2>/dev/null || echo 10000)
1763
1764 # don't even bother if the FD limit is too high (256 on some macOS)
1765 [ "$MAX" -lt 300 ] || exit 0
1766
1767 c="echo hi"
1768 for n in $(seq 3 $MAX)
1769 do
1770 c="{ $c; echo hi; } >file_$n"
1771 done
1772
1773 eval $c 2>err
1774 [ -s err ] || exit 3
1775 rm file_*
1776
1777 #### semantics.redir.to.test
1778 set -e
1779 echo hi >file
1780 [ -s file ]
1781 [ "$(cat file)" = "hi" ]
1782 rm file
1783
1784 #### semantics.return.and.test
1785 f() {
1786 return 5 && echo fail passthrough
1787 }
1788 f
1789 echo $?
1790
1791
1792 ## STDOUT:
1793 5
1794 ## END
1795
1796 #### semantics.return.if.test
1797 # id:ce0c3ef7-66a9-08de-546f-d8ef8263b6da@gigawatt.nl
1798 # from Harald van Dijk
1799
1800 f() {
1801 if ! return 5
1802 then echo fail then; exit
1803 else echo fail else; exit
1804 fi
1805 }
1806 f
1807 echo $?
1808
1809 g() {
1810 if return 6
1811 then echo fail then2; exit
1812 else echo fail else2; exit
1813 fi
1814 }
1815 g
1816 echo $?
1817 ## STDOUT:
1818 5
1819 6
1820 ## END
1821
1822 #### semantics.return.not.test
1823 f() {
1824 ! return 5
1825 echo fail passthrough
1826 }
1827 f
1828 echo $?
1829
1830
1831
1832 #### semantics.return.or.test
1833 f() {
1834 return 5 || echo fail passthrough
1835 }
1836 f
1837 echo $?
1838
1839
1840 ## STDOUT:
1841 5
1842 ## END
1843
1844 #### semantics.return.trap.test
1845 # Robert Elz <kre@munnari.OZ.AU> (2020-03-16) (inbox list unread)
1846 # Subject: Re: XCU: 'exit' trap condition [was:Re: XCU: 'return' from subshell]
1847 # To: Joerg Schilling <Joerg.Schilling@fokus.fraunhofer.de>
1848 # Cc: fieldhouse@gmx.net, austin-group-l@opengroup.org
1849 # Date: Mon, 16 Mar 2020 22:15:10 +0700
1850
1851 f() ( trap "echo FOO" EXIT; return 5; echo BAR )
1852 f
1853
1854 ## STDOUT:
1855 FOO
1856 ## END
1857
1858 #### semantics.return.while.test
1859 f() {
1860 while return 5
1861 do
1862 echo fail while
1863 break
1864 done
1865 }
1866 f
1867 echo $?
1868
1869 g() {
1870 while ! return 6
1871 do
1872 echo fail while
1873 break
1874 done
1875 }
1876 g
1877 echo $?
1878 ## STDOUT:
1879 5
1880 6
1881 ## END
1882
1883 #### semantics.simple.link.test
1884 set -e
1885 echo 'echo hi' >cmd.sh
1886 chmod +x cmd.sh
1887 ln -s cmd.sh link.sh
1888 OLDPATH=$PATH
1889 PATH=.
1890 [ -x cmd.sh ]
1891 [ -L link.sh ]
1892 cmd.sh # command works
1893 link.sh # symlink works
1894 PATH=$OLDPATH
1895 ls
1896 rm cmd.sh link.sh
1897 ## STDOUT:
1898 hi
1899 hi
1900 cmd.sh
1901 link.sh
1902 ## END
1903
1904 #### semantics.slash.glob.test
1905 arg_len() {
1906 echo $#
1907 }
1908
1909 trap 'rm -r foo' EXIT
1910
1911 mkdir foo
1912 touch foo/a foo/b foo/c
1913 [ "$(arg_len foo//*)" -eq 3 ] && echo OK
1914
1915 ## STDOUT:
1916 OK
1917 ## END
1918
1919 #### semantics.special.assign.visible.nonposix.test
1920 x=5 y=$((x+2)) :
1921 echo $x $y
1922
1923 ## STDOUT:
1924 5 7
1925 ## END
1926
1927 #### semantics.splitting.ifs.test
1928 cat << EOF > input
1929 -,1-,-2,-,3,-
1930 EOF
1931
1932 IFS="-,"
1933 echo `cat input`
1934 ## STDOUT:
1935 1 2 3
1936 ## END
1937
1938 #### semantics.subshell.background.traps.test
1939 (trap - INT; echo INT sleeping...; sleep 10; echo INT awake) & pid=$!
1940 sleep 1
1941 kill $pid
1942 wait $pid
1943 ec=$?
1944 [ "$ec" -ge 128 ] || exit 1
1945 (trap - QUIT; echo QUIT sleeping...; sleep 10; echo QUIT awake) & pid=$!
1946 sleep 1
1947 kill -QUIT $pid
1948 wait $pid
1949 ec=$?
1950 [ "$ec" -ge 128 ] || exit 2
1951 ## STDOUT:
1952 INT sleeping...
1953 QUIT sleeping...
1954 ## END
1955
1956 #### semantics.subshell.break.test
1957 # https://www.spinics.net/lists/dash/msg01773.html
1958 for x in a b
1959 do
1960 (
1961 for y in c d
1962 do
1963 break 2
1964 done
1965 echo $x
1966 )
1967 done
1968 ## STDOUT:
1969 a
1970 b
1971 ## END
1972
1973 #### semantics.subshell.redirect.test
1974 # Ensure that the exit trap is ran with the redirections still active.
1975 (trap 'echo foo' EXIT) >/dev/null
1976
1977 ## stdout-json: ""
1978
1979 #### semantics.subshell.return2.test
1980 # Dirk Fieldhouse <fieldhouse@gmx.net> (2020-03-11) (junk list)
1981 # Subject: Re: XCU: 'return' from subshell
1982 # To: Austin Group <austin-group-l@opengroup.org>
1983 # Cc: chet.ramey@case.edu, Robert Elz <kre@munnari.OZ.AU>
1984 # Date: Wed, 11 Mar 2020 14:49:31 +0000
1985
1986 f1() {
1987 ( echo foo; return )
1988 echo bar
1989 }
1990
1991 f1
1992 ## STDOUT:
1993 foo
1994 bar
1995 ## END
1996
1997 #### semantics.subshell.return.test
1998 # Stephane Chazelas <stephane@chazelas.org> (2020-03-11) (list)
1999 # Subject: Re: XCU: 'return' from subshell
2000 # To: Robert Elz <kre@munnari.OZ.AU>
2001 # Cc: Dirk Fieldhouse <fieldhouse@gmx.net>, Austin Group <austin-group-l@opengroup.org>
2002 # Date: Wed, 11 Mar 2020 06:37:41 +0000
2003
2004 f() { (return 42; echo x); echo "$?"; }; f
2005
2006 ## STDOUT:
2007 42
2008 ## END
2009
2010 #### semantics.substring.quotes.test
2011 FOO="a?b"
2012 [ "${FOO#*"?"}" = b ] && echo OK1
2013 FOO="abc"
2014 [ "${FOO#"${FOO%???}"}" = "$FOO" ] && echo OK2
2015
2016 ## STDOUT:
2017 OK1
2018 OK2
2019 ## END
2020
2021 #### semantics.tilde.colon.test
2022 tilde=~
2023 cat << EOF >test_script
2024 var=:~
2025 [ "\$var" = ":$tilde" ]
2026 EOF
2027 chmod +x test_script
2028 $TEST_SHELL test_script
2029
2030 #### semantics.tilde.no-exp.test
2031 echo hi:~
2032 x=:
2033 echo hello${x}~
2034
2035 ## STDOUT:
2036 hi:~
2037 hello:~
2038 ## END
2039
2040 #### semantics.tilde.quoted.prefix.test
2041 # ADDTOPOSIX
2042
2043 set -e
2044 tilde=$(echo ~)
2045 [ "$tilde" = "$HOME" ] || exit 1
2046
2047 funny='~'\""$LOGNAME"\"
2048 exp=$(eval "echo $funny")
2049 [ "$exp" = "~$LOGNAME" ] || exit 2
2050
2051 [ ~/ = "$HOME"/ ] || exit 3
2052
2053 echo ok
2054 ## STDOUT:
2055 ok
2056 ## END
2057
2058 #### semantics.tilde.quoted.test
2059 HOME="weird times"
2060 printf '%s\n' ~
2061 touch a1 a2 a3
2062 HOME='a*'
2063 printf '%s\n' ~
2064
2065 ## STDOUT:
2066 weird times
2067 a*
2068 ## END
2069
2070 #### semantics.tilde.sep.test
2071 # ADDTOPOSIX
2072 [ ~: = "~:" ] || exit 1
2073
2074 y=~
2075 [ $y = "$HOME" ] || exit 2
2076
2077 y=~/foo
2078 [ $y = "$HOME/foo" ] || exit 3
2079
2080 y=~:foo
2081 [ $y = "$HOME:foo" ] || exit 4
2082
2083 y=foo:~
2084 [ $y = "foo:$HOME" ] || exit 5
2085
2086 y=foo:~:bar
2087 [ $y = "foo:$HOME:bar" ] || exit 6
2088
2089 echo ok
2090 ## STDOUT:
2091 ok
2092 ## END
2093
2094 #### semantics.tilde.test
2095 echo ~ >tilde.out
2096 var=~
2097 echo $var > var.out
2098 [ -f tilde.out ] && [ -f var.out ] && \
2099 [ -s tilde.out ] && [ -s var.out ] && \
2100 [ $(cat tilde.out) = $(cat var.out) ] && \
2101 [ $(cat tilde.out) != "~" ]
2102
2103
2104
2105 #### semantics.traps.async.test
2106 (
2107 kill -s QUIT $($TEST_SHELL -c 'echo $PPID') || exit 1
2108 echo done
2109 ) &
2110 wait $!
2111
2112 ## STDOUT:
2113 done
2114 ## END
2115
2116 #### semantics.traps.inherit.test
2117 (
2118 trap "echo got SIGINT" INT
2119
2120 # default trap will mean we actually get a QUIT, overriding the default on asyncs
2121 trap - QUIT
2122
2123 mypid=$($TEST_SHELL -c 'echo $PPID')
2124
2125 # this can be overridden
2126 kill -s INT "$mypid" || exit 4
2127
2128 # will kill this shell,
2129 echo "sending SIGQUIT"
2130 kill -s QUIT "$mypid" || exit 2
2131 exit 0
2132 ) &
2133 wait $!
2134 echo $?
2135
2136
2137 ## STDOUT:
2138 got SIGINT
2139 sending SIGQUIT
2140 131
2141 ## END
2142
2143 #### semantics.var.alt.nullifs.test
2144 IFS=
2145 printf '<%s>\n' ${x+uhoh} a b
2146
2147 f() { echo $#; printf '<%s>\n' "$@" ; }
2148 f ${x+uhoh} a b
2149
2150 x=hi
2151 f ${x+uhoh} a b
2152
2153
2154 ## STDOUT:
2155 <a>
2156 <b>
2157 2
2158 <a>
2159 <b>
2160 3
2161 <uhoh>
2162 <a>
2163 <b>
2164 ## END
2165
2166 #### semantics.var.alt.null.test
2167 f() { echo $# ; }
2168 unset -v nonesuch
2169 f ${nonesuch+nonempty} a b
2170
2171 x=foo
2172 f ${x+hi} a b
2173
2174 ## STDOUT:
2175 2
2176 3
2177 ## END
2178
2179 #### semantics.varassign.test
2180 # https://git.kernel.org/pub/scm/utils/dash/dash.git/commit/?id=a29e9a1738a4e7040211842f3f3d90e172fa58ce
2181 foo=bar; echo ${foo=BUG}; echo $foo
2182
2183 ## STDOUT:
2184 bar
2185 bar
2186 ## END
2187
2188 #### semantics.var.builtin.nonspecial.test
2189 # successful command
2190 unset x
2191 x=value command alias >/dev/null 2>&1
2192 echo ${x-unset}
2193 test -z "$x" || exit 1
2194
2195 # unsuccessful command
2196 unset x
2197 x=value command alias -: >/dev/null 2>&1
2198 echo ${x-unset}
2199 test -z "$x" || exit 2
2200
2201 ## STDOUT:
2202 unset
2203 unset
2204 ## END
2205
2206 #### semantics.var.dashu.test
2207 unset nonesuch
2208 $TEST_SHELL -u -c 'echo $nonesuch' && exit 1
2209 $TEST_SHELL -u -c 'echo $3' && exit 1
2210 $TEST_SHELL -u -c 'var=val ; echo ${var+$nonesuch}' && exit 1
2211 $TEST_SHELL -u -c 'echo $(($nonesuch + 1))' && exit 1
2212 $TEST_SHELL -u -c 'echo $((nonesuch + 1))' && exit 1
2213 $TEST_SHELL -u -c 'echo ${#nonesuch}' && exit 1
2214 echo passed
2215
2216 ## STDOUT:
2217 passed
2218 ## END
2219
2220 #### semantics.var.format.tilde.test
2221 unset x
2222 tilde=~
2223 : ${x:=~}
2224 ext=~/foo
2225 [ "$x" = "$tilde" ] && \
2226 [ "/foo" = ${ext#~} ] && \
2227 ! $TEST_SHELL -c 'echo ${y?~}'
2228
2229 #### semantics.variable.escape.length.test
2230 x=\n
2231 echo ${#x}
2232 x=\\n
2233 echo ${#x}
2234
2235 ## STDOUT:
2236 1
2237 2
2238 ## END
2239
2240 #### semantics.var.ifs.sep.test
2241 IFS=", "
2242 set 1 2 3
2243 echo "$*"
2244
2245 ## STDOUT:
2246 1,2,3
2247 ## END
2248
2249 #### semantics.var.star.emptyifs.test
2250 IFS=""
2251 bee="b e e"
2252 set a "$bee" c
2253
2254 printf '<%s>\n' $*
2255 printf '<%s>\n' HI$*BYE
2256
2257 ## STDOUT:
2258 <a>
2259 <b e e>
2260 <c>
2261 <HIa>
2262 <b e e>
2263 <cBYE>
2264 ## END
2265
2266 #### semantics.var.star.format.test
2267 sp="s p aces"
2268 tn=$(printf '%b' 'and\ttabs\n and newlines')
2269 set -- a "$sp" b c "$tn"
2270 IFS=": "
2271 printf '<%s>\n' "${var=$*}"
2272 unset var
2273 unset IFS
2274 printf '<%s>\n' "${var=$*}"
2275
2276 ## STDOUT:
2277 <a:s p aces:b:c:and tabs
2278 and newlines>
2279 <a s p aces b c and tabs
2280 and newlines>
2281 ## END
2282
2283 #### semantics.var.unset.nofield.test
2284 count() { echo $#; }
2285 [ $(count a $nonesuch b) -eq 2 ]
2286
2287 #### semantics.wait.alreadydead.test
2288 sleep 10 &
2289 pid=$!
2290 sleep 1
2291 kill $pid
2292 echo kill ec: $?
2293 sleep 1
2294 wait $pid
2295 echo wait ec: $?
2296
2297 ## STDOUT:
2298 kill ec: 0
2299 wait ec: 143
2300 ## END
2301
2302 #### semantics.while.test
2303 i=0
2304 while [ $i -lt 10 ]
2305 do
2306 i=$((i + 1))
2307 echo $i
2308 done
2309 echo $?
2310 i=0
2311 while [ $i -lt 10 ]
2312 do
2313 i=$((i + 1))
2314 echo $i;
2315 false
2316 done
2317 echo $?
2318
2319 ## STDOUT:
2320 1
2321 2
2322 3
2323 4
2324 5
2325 6
2326 7
2327 8
2328 9
2329 10
2330 0
2331 1
2332 2
2333 3
2334 4
2335 5
2336 6
2337 7
2338 8
2339 9
2340 10
2341 1
2342 ## END
2343
2344 #### sh.-c.arg0.test
2345 cat > scr <<EOF
2346 echo "i am \$0, hear me roar"
2347 EOF
2348 $TEST_SHELL -c '. "$0"' ./scr
2349 ## STDOUT:
2350 i am ./scr, hear me roar
2351 ## END
2352
2353 #### sh.env.ppid.test
2354 $TEST_SHELL -c 'echo $PPID' >ppid
2355 inner=$(cat ppid)
2356 rm ppid
2357 [ "$inner" -eq "$$" ]
2358
2359
2360
2361 #### sh.file.weirdness.test
2362 $TEST_SHELL nonesuch
2363 echo 'echo works' >scr
2364 $TEST_SHELL scr
2365 $TEST_SHELL ./scr
2366 echo 'echo nope' >scr
2367 chmod -r scr
2368 $TEST_SHELL ./scr && exit 1
2369 $TEST_SHELL scr && exit 1
2370 rm -f scr
2371
2372
2373 ## STDOUT:
2374 works
2375 works
2376 ## END
2377
2378 #### sh.monitor.bg.test
2379 set -m
2380
2381 start=$(date "+%s")
2382 sleep 3 & pid=$!
2383 kill -TSTP $pid
2384 jobs -l
2385 stop=$(date "+%s")
2386 elapsed=$((stop - start))
2387 echo $stop - $start = $elapsed
2388 [ $((elapsed)) -lt 2 ] || exit 1
2389
2390 jobs -l
2391 bg >output
2392
2393 stop2=$(date "+%s")
2394 elapsed=$((stop2 - start))
2395 echo $stop2 - $start = $elapsed
2396 [ $((elapsed)) -lt 2 ] || exit 2
2397 grep "[1]" output || exit 3
2398 grep "sleep 3" output || exit 4
2399
2400 wait
2401
2402 stop3=$(date "+%s")
2403 elapsed=$((stop3 - start))
2404 echo $stop3 - $start = $elapsed
2405 [ $((elapsed)) -ge 3 ] || exit 5
2406
2407
2408 #### sh.monitor.fg.test
2409 set -m
2410
2411 start=$(date "+%s")
2412 sleep 3 & pid=$!
2413 kill -TSTP $pid
2414 jobs -l
2415 stop=$(date "+%s")
2416 elapsed=$((stop - start))
2417 echo $stop - $start = $elapsed
2418 [ $((elapsed)) -lt 2 ] || exit 1
2419
2420 jobs -l
2421 fg >output
2422
2423 stop2=$(date "+%s")
2424 elapsed=$((stop2 - start))
2425 echo $stop2 - $start = $elapsed
2426 [ $((elapsed)) -ge 3 ] || exit 2
2427 grep "sleep 3" output || exit 3
2428
2429
2430 #### sh.set.ifs.test
2431 cat >show_ifs <<EOF
2432 printf '%s' "$IFS"
2433 EOF
2434 $TEST_SHELL show_ifs || exit 1
2435 export IFS=123
2436 $TEST_SHELL show_ifs || exit 1
2437 IFS=abc $TEST_SHELL show_ifs || exit 1
2438
2439 ## STDOUT:
2440
2441
2442
2443 ## END
2444