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