17c2fbfb3SApril Chin######################################################################## 27c2fbfb3SApril Chin# # 37c2fbfb3SApril Chin# This software is part of the ast package # 4*b30d1939SAndy Fiddaman# Copyright (c) 1982-2012 AT&T Intellectual Property # 57c2fbfb3SApril Chin# and is licensed under the # 6*b30d1939SAndy Fiddaman# Eclipse Public License, Version 1.0 # 77c2fbfb3SApril Chin# by AT&T Intellectual Property # 87c2fbfb3SApril Chin# # 97c2fbfb3SApril Chin# A copy of the License is available at # 10*b30d1939SAndy Fiddaman# http://www.eclipse.org/org/documents/epl-v10.html # 11*b30d1939SAndy Fiddaman# (with md5 checksum b35adb5213ca9657e911e9befb180842) # 127c2fbfb3SApril Chin# # 137c2fbfb3SApril Chin# Information and Software Systems Research # 147c2fbfb3SApril Chin# AT&T Research # 157c2fbfb3SApril Chin# Florham Park NJ # 167c2fbfb3SApril Chin# # 177c2fbfb3SApril Chin# David Korn <dgk@research.att.com> # 187c2fbfb3SApril Chin# # 197c2fbfb3SApril Chin######################################################################## 207c2fbfb3SApril Chinfunction err_exit 217c2fbfb3SApril Chin{ 227c2fbfb3SApril Chin print -u$Error_fd -n "\t" 237c2fbfb3SApril Chin print -u$Error_fd -r ${Command}[$1]: "${@:2}" 247c2fbfb3SApril Chin (( Errors+=1 )) 257c2fbfb3SApril Chin} 267c2fbfb3SApril Chinalias err_exit='err_exit $LINENO' 2734f9b3eeSRoland Mainz 287c2fbfb3SApril ChinCommand=${0##*/} 297c2fbfb3SApril Chininteger Errors=0 Error_fd=2 307c2fbfb3SApril Chin 3134f9b3eeSRoland Mainztmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } 3234f9b3eeSRoland Mainztrap "cd /; rm -rf $tmp" EXIT 3334f9b3eeSRoland Mainz 34*b30d1939SAndy Fiddamanbuiltin getconf 3534f9b3eeSRoland Mainzbincat=$(PATH=$(getconf PATH) whence -p cat) 3634f9b3eeSRoland Mainz 377c2fbfb3SApril Chinz=() 387c2fbfb3SApril Chinz.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi) 397c2fbfb3SApril Chinz.bar[0]=hello 407c2fbfb3SApril Chinz.bar[2]=world 417c2fbfb3SApril Chinz.bar[1]=(x=4 y=5) 427c2fbfb3SApril Chinval='( 437c2fbfb3SApril Chin typeset -a bar=( 447c2fbfb3SApril Chin [0]=hello 457c2fbfb3SApril Chin [2]=world 467c2fbfb3SApril Chin [1]=( 477c2fbfb3SApril Chin x=4 487c2fbfb3SApril Chin y=5 497c2fbfb3SApril Chin ) 507c2fbfb3SApril Chin ) 517c2fbfb3SApril Chin typeset -A foo=( 527c2fbfb3SApril Chin [one]=hello 537c2fbfb3SApril Chin [three]=hi 547c2fbfb3SApril Chin [two]=( 557c2fbfb3SApril Chin x=3 567c2fbfb3SApril Chin y=4 577c2fbfb3SApril Chin ) 587c2fbfb3SApril Chin ) 597c2fbfb3SApril Chin)' 607c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable with mixed arrays not working' 617c2fbfb3SApril Chinz.bar[1]=yesyes 627c2fbfb3SApril Chin[[ ${z.bar[1]} == yesyes ]] || err_exit 'reassign of index array compound variable fails' 637c2fbfb3SApril Chinz.bar[1]=(x=12 y=5) 647c2fbfb3SApril Chin[[ ${z.bar[1]} == $'(\n\tx=12\n\ty=5\n)' ]] || err_exit 'reassign array simple to compound variable fails' 657c2fbfb3SApril Chineval val="$z" 667c2fbfb3SApril Chin( 677c2fbfb3SApril Chin z.foo[three]=good 687c2fbfb3SApril Chin [[ ${z.foo[three]} == good ]] || err_exit 'associative array assignment in subshell not working' 697c2fbfb3SApril Chin) 707c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' 717c2fbfb3SApril Chineval val="$z" 727c2fbfb3SApril Chin( 737c2fbfb3SApril Chin z.foo[two]=ok 747c2fbfb3SApril Chin [[ ${z.foo[two]} == ok ]] || err_exit 'associative array assignment to compound variable in subshell not working' 757c2fbfb3SApril Chin z.bar[1]=yes 767c2fbfb3SApril Chin [[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working' 777c2fbfb3SApril Chin) 787c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' 7934f9b3eeSRoland Mainz 807c2fbfb3SApril Chinx=( 817c2fbfb3SApril Chin foo=( qqq=abc rrr=def) 827c2fbfb3SApril Chin bar=( zzz=no rst=fed) 837c2fbfb3SApril Chin) 847c2fbfb3SApril Chineval val="$x" 857c2fbfb3SApril Chin( 867c2fbfb3SApril Chin unset x.foo 877c2fbfb3SApril Chin [[ ${x.foo.qqq} ]] && err_exit 'x.foo.qqq should be unset' 887c2fbfb3SApril Chin x.foo=good 897c2fbfb3SApril Chin [[ ${x.foo} == good ]] || err_exit 'x.foo should be good' 907c2fbfb3SApril Chin) 917c2fbfb3SApril Chin[[ $x == "$val" ]] || err_exit 'compound variable changes after unset leaves' 927c2fbfb3SApril Chinunset l 937c2fbfb3SApril Chin( 947c2fbfb3SApril Chin l=( a=1 b="BE" ) 957c2fbfb3SApril Chin) 967c2fbfb3SApril Chin[[ ${l+foo} != foo ]] || err_exit 'l should be unset' 977c2fbfb3SApril Chin 987c2fbfb3SApril ChinError_fd=9 997c2fbfb3SApril Chineval "exec $Error_fd>&2 2>/dev/null" 1007c2fbfb3SApril Chin 1017c2fbfb3SApril ChinTEST_notfound=notfound 1027c2fbfb3SApril Chinwhile whence $TEST_notfound >/dev/null 2>&1 1037c2fbfb3SApril Chindo TEST_notfound=notfound-$RANDOM 1047c2fbfb3SApril Chindone 1057c2fbfb3SApril Chin 106*b30d1939SAndy Fiddaman 1077c2fbfb3SApril Chininteger BS=1024 nb=64 ss=60 bs no 1087c2fbfb3SApril Chinfor bs in $BS 1 1097c2fbfb3SApril Chindo $SHELL -c ' 1107c2fbfb3SApril Chin { 1117c2fbfb3SApril Chin sleep '$ss' 1127c2fbfb3SApril Chin kill -KILL $$ 1137c2fbfb3SApril Chin } & 1147c2fbfb3SApril Chin set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs') 1157c2fbfb3SApril Chin print ${#1} 1167c2fbfb3SApril Chin kill $! 11734f9b3eeSRoland Mainz ' > $tmp/sub 2>/dev/null 11834f9b3eeSRoland Mainz no=$(<$tmp/sub) 1197c2fbfb3SApril Chin (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs -- expected $((BS*nb)), got ${no:-0}" 1207c2fbfb3SApril Chindone 1217c2fbfb3SApril Chin# this time with redirection on the trailing command 1227c2fbfb3SApril Chinfor bs in $BS 1 1237c2fbfb3SApril Chindo $SHELL -c ' 1247c2fbfb3SApril Chin { 1257c2fbfb3SApril Chin sleep 2 1267c2fbfb3SApril Chin sleep '$ss' 1277c2fbfb3SApril Chin kill -KILL $$ 1287c2fbfb3SApril Chin } & 1297c2fbfb3SApril Chin set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs' 2>/dev/null) 1307c2fbfb3SApril Chin print ${#1} 1317c2fbfb3SApril Chin kill $! 13234f9b3eeSRoland Mainz ' > $tmp/sub 2>/dev/null 13334f9b3eeSRoland Mainz no=$(<$tmp/sub) 1347c2fbfb3SApril Chin (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs and trailing redirection -- expected $((BS*nb)), got ${no:-0}" 1357c2fbfb3SApril Chindone 1367c2fbfb3SApril Chin 1377c2fbfb3SApril Chin# exercise command substitutuion trailing newline logic w.r.t. pipe vs. tmp file io 1387c2fbfb3SApril Chin 1397c2fbfb3SApril Chinset -- \ 1407c2fbfb3SApril Chin 'post-line print' \ 1417c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; print 1); print' \ 1427c2fbfb3SApril Chin 1 \ 1437c2fbfb3SApril Chin 'pre-line print' \ 1447c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; print); print 1' \ 1457c2fbfb3SApril Chin $'\n1' \ 1467c2fbfb3SApril Chin 'multiple pre-line print' \ 1477c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; print); print; ($TEST_fork; print 1); print' \ 1487c2fbfb3SApril Chin $'\n\n1' \ 1497c2fbfb3SApril Chin 'multiple post-line print' \ 1507c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print); print' \ 1517c2fbfb3SApril Chin 1 \ 1527c2fbfb3SApril Chin 'intermediate print' \ 1537c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print 2); print' \ 1547c2fbfb3SApril Chin $'1\n\n2' \ 1557c2fbfb3SApril Chin 'simple variable' \ 1567c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; l=2; print "$l"); print $l' \ 1577c2fbfb3SApril Chin 2 \ 1587c2fbfb3SApril Chin 'compound variable' \ 1597c2fbfb3SApril Chin '$TEST_unset; ($TEST_fork; l=(a=2 b="BE"); print "$l"); print $l' \ 1607c2fbfb3SApril Chin $'(\n\ta=2\n\tb=BE\n)' \ 1617c2fbfb3SApril Chin 1627c2fbfb3SApril Chinexport TEST_fork TEST_unset 1637c2fbfb3SApril Chin 1647c2fbfb3SApril Chinwhile (( $# >= 3 )) 1657c2fbfb3SApril Chindo txt=$1 1667c2fbfb3SApril Chin cmd=$2 1677c2fbfb3SApril Chin exp=$3 1687c2fbfb3SApril Chin shift 3 1697c2fbfb3SApril Chin for TEST_unset in '' 'unset var' 1707c2fbfb3SApril Chin do for TEST_fork in '' 'ulimit -c 0' 1717c2fbfb3SApril Chin do for TEST_shell in "eval" "$SHELL -c" 1727c2fbfb3SApril Chin do if ! got=$($TEST_shell "$cmd") 1737c2fbfb3SApril Chin then err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt print failed" 1747c2fbfb3SApril Chin elif [[ "$got" != "$exp" ]] 1757c2fbfb3SApril Chin then EXP=$(printf %q "$exp") 1767c2fbfb3SApril Chin GOT=$(printf %q "$got") 1777c2fbfb3SApril Chin err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt command substitution failed -- expected $EXP, got $GOT" 1787c2fbfb3SApril Chin fi 1797c2fbfb3SApril Chin done 1807c2fbfb3SApril Chin done 1817c2fbfb3SApril Chin done 1827c2fbfb3SApril Chindone 1837c2fbfb3SApril Chin 1847c2fbfb3SApril Chinr=$( ($SHELL -c ' 1857c2fbfb3SApril Chin { 1867c2fbfb3SApril Chin sleep 32 1877c2fbfb3SApril Chin kill -KILL $$ 1887c2fbfb3SApril Chin } & 1897c2fbfb3SApril Chin for v in $(set | sed "s/=.*//") 1907c2fbfb3SApril Chin do command unset $v 1917c2fbfb3SApril Chin done 1927c2fbfb3SApril Chin typeset -Z5 I 1937c2fbfb3SApril Chin for ((I = 0; I < 1024; I++)) 1947c2fbfb3SApril Chin do eval A$I=1234567890 1957c2fbfb3SApril Chin done 1967c2fbfb3SApril Chin a=$(set 2>&1) 1977c2fbfb3SApril Chin print ok 1987c2fbfb3SApril Chin kill -KILL $! 1997c2fbfb3SApril Chin') 2>/dev/null) 2007c2fbfb3SApril Chin[[ $r == ok ]] || err_exit "large subshell command substitution hangs" 2017c2fbfb3SApril Chin 2027c2fbfb3SApril Chinfor TEST_command in '' $TEST_notfound 2037c2fbfb3SApril Chindo for TEST_exec in '' 'exec' 2047c2fbfb3SApril Chin do for TEST_fork in '' 'ulimit -c 0;' 2057c2fbfb3SApril Chin do for TEST_redirect in '' '>/dev/null' 2067c2fbfb3SApril Chin do for TEST_substitute in '' ': $' 2077c2fbfb3SApril Chin do 2087c2fbfb3SApril Chin 2097c2fbfb3SApril Chin TEST_test="$TEST_substitute($TEST_fork $TEST_exec $TEST_command $TEST_redirect)" 2107c2fbfb3SApril Chin [[ $TEST_test == '('*([[:space:]])')' ]] && continue 2117c2fbfb3SApril Chin r=$($SHELL -c ' 2127c2fbfb3SApril Chin { 2137c2fbfb3SApril Chin sleep 2 2147c2fbfb3SApril Chin kill -KILL $$ 2157c2fbfb3SApril Chin } & 2167c2fbfb3SApril Chin '"$TEST_test"' 2177c2fbfb3SApril Chin kill $! 2187c2fbfb3SApril Chin print ok 2197c2fbfb3SApril Chin ') 2207c2fbfb3SApril Chin [[ $r == ok ]] || err_exit "shell hangs on $TEST_test" 2217c2fbfb3SApril Chin 2227c2fbfb3SApril Chin done 2237c2fbfb3SApril Chin done 2247c2fbfb3SApril Chin done 2257c2fbfb3SApril Chin done 2267c2fbfb3SApril Chindone 2277c2fbfb3SApril Chin 22834f9b3eeSRoland Mainz$SHELL -c '( autoload xxxxx);print -n' || err_exit 'autoloaded functions in subshells can cause failure' 22934f9b3eeSRoland Mainzfoo=$($SHELL <<- ++EOF++ 23034f9b3eeSRoland Mainz (trap 'print bar' EXIT;print -n foo) 23134f9b3eeSRoland Mainz ++EOF++ 23234f9b3eeSRoland Mainz) 23334f9b3eeSRoland Mainz[[ $foo == foobar ]] || err_exit 'trap on exit when last commands is subshell is not triggered' 23434f9b3eeSRoland Mainz 23534f9b3eeSRoland Mainzerr=$( 23634f9b3eeSRoland Mainz $SHELL 2>&1 <<- \EOF 23734f9b3eeSRoland Mainz date=$(whence -p date) 23834f9b3eeSRoland Mainz function foo 23934f9b3eeSRoland Mainz { 24034f9b3eeSRoland Mainz x=$( $date > /dev/null 2>&1 ;:) 24134f9b3eeSRoland Mainz } 24234f9b3eeSRoland Mainz # consume almost all fds to push the test to the fd limit # 24334f9b3eeSRoland Mainz integer max=$(ulimit --nofile) 24434f9b3eeSRoland Mainz (( max -= 6 )) 24534f9b3eeSRoland Mainz for ((i=20; i < max; i++)) 24634f9b3eeSRoland Mainz do exec {i}>&1 24734f9b3eeSRoland Mainz done 24834f9b3eeSRoland Mainz for ((i=0; i < 20; i++)) 24934f9b3eeSRoland Mainz do y=$(foo) 25034f9b3eeSRoland Mainz done 25134f9b3eeSRoland Mainz EOF 25234f9b3eeSRoland Mainz) || { 25334f9b3eeSRoland Mainz err=${err%%$'\n'*} 25434f9b3eeSRoland Mainz err=${err#*:} 25534f9b3eeSRoland Mainz err=${err##[[:space:]]} 25634f9b3eeSRoland Mainz err_exit "nested command substitution with redirections failed -- $err" 25734f9b3eeSRoland Mainz} 25834f9b3eeSRoland Mainz 25934f9b3eeSRoland Mainzexp=0 26034f9b3eeSRoland Mainz$SHELL -c $' 26134f9b3eeSRoland Mainz function foobar 26234f9b3eeSRoland Mainz { 26334f9b3eeSRoland Mainz print "hello world" 26434f9b3eeSRoland Mainz } 26534f9b3eeSRoland Mainz [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] 26634f9b3eeSRoland Mainz exit '$exp$' 26734f9b3eeSRoland Mainz' 26834f9b3eeSRoland Mainzgot=$? 26934f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" 27034f9b3eeSRoland Mainzexp=ok 27134f9b3eeSRoland Mainzgot=$($SHELL -c $' 27234f9b3eeSRoland Mainz function foobar 27334f9b3eeSRoland Mainz { 27434f9b3eeSRoland Mainz print "hello world" 27534f9b3eeSRoland Mainz } 27634f9b3eeSRoland Mainz [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] 27734f9b3eeSRoland Mainz print '$exp$' 27834f9b3eeSRoland Mainz') 27934f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" 28034f9b3eeSRoland Mainz 28134f9b3eeSRoland Mainz# command substitution variations # 28234f9b3eeSRoland Mainzset -- \ 28334f9b3eeSRoland Mainz '$(' ')' \ 28434f9b3eeSRoland Mainz '${ ' '; }' \ 28534f9b3eeSRoland Mainz '$(ulimit -c 0; ' ')' \ 28634f9b3eeSRoland Mainz '$( (' ') )' \ 28734f9b3eeSRoland Mainz '${ (' '); }' \ 28834f9b3eeSRoland Mainz '`' '`' \ 28934f9b3eeSRoland Mainz '`(' ')`' \ 29034f9b3eeSRoland Mainz '`ulimit -c 0; ' '`' \ 29134f9b3eeSRoland Mainz # end of table # 29234f9b3eeSRoland Mainzexp=ok 29334f9b3eeSRoland Mainztestcase[1]=' 29434f9b3eeSRoland Mainz if %sexpr "NOMATCH" : ".*Z" >/dev/null%s 29534f9b3eeSRoland Mainz then print error 29634f9b3eeSRoland Mainz else print ok 29734f9b3eeSRoland Mainz fi 29834f9b3eeSRoland Mainz exit %s 29934f9b3eeSRoland Mainz' 30034f9b3eeSRoland Mainztestcase[2]=' 30134f9b3eeSRoland Mainz function bar 30234f9b3eeSRoland Mainz { 30334f9b3eeSRoland Mainz pipeout=%1$sprintf Ok | tr O o%2$s 30434f9b3eeSRoland Mainz print $pipeout 30534f9b3eeSRoland Mainz return 0 30634f9b3eeSRoland Mainz } 30734f9b3eeSRoland Mainz foo=%1$sbar%2$s || foo="exit status $?" 30834f9b3eeSRoland Mainz print $foo 30934f9b3eeSRoland Mainz exit %3$s 31034f9b3eeSRoland Mainz' 31134f9b3eeSRoland Mainzwhile (( $# >= 2 )) 31234f9b3eeSRoland Mainzdo for ((TEST=1; TEST<=${#testcase[@]}; TEST++)) 31334f9b3eeSRoland Mainz do body=${testcase[TEST]} 31434f9b3eeSRoland Mainz for code in 0 2 31534f9b3eeSRoland Mainz do got=${ printf "$body" "$1" "$2" "$code" | $SHELL 2>&1 } 31634f9b3eeSRoland Mainz status=$? 31734f9b3eeSRoland Mainz if (( status != code )) 31834f9b3eeSRoland Mainz then err_exit "test $TEST '$1...$2 exit $code' failed -- exit status $status, expected $code" 31934f9b3eeSRoland Mainz elif [[ $got != $exp ]] 32034f9b3eeSRoland Mainz then err_exit "test $TEST '$1...$2 exit $code' failed -- got '$got', expected '$exp'" 32134f9b3eeSRoland Mainz fi 32234f9b3eeSRoland Mainz done 32334f9b3eeSRoland Mainz done 32434f9b3eeSRoland Mainz shift 2 32534f9b3eeSRoland Mainzdone 32634f9b3eeSRoland Mainz 32734f9b3eeSRoland Mainz# the next tests loop on all combinations of 32834f9b3eeSRoland Mainz# { SUB CAT INS TST APP } X { file-sizes } 32934f9b3eeSRoland Mainz# where the file size starts at 1Ki and doubles up to and including 1Mi 33034f9b3eeSRoland Mainz# 33134f9b3eeSRoland Mainz# the tests and timeouts are done in async subshells to prevent 33234f9b3eeSRoland Mainz# the test harness from hanging 33334f9b3eeSRoland Mainz 33434f9b3eeSRoland MainzSUB=( 33534f9b3eeSRoland Mainz ( BEG='$( ' END=' )' ) 33634f9b3eeSRoland Mainz ( BEG='${ ' END='; }' ) 33734f9b3eeSRoland Mainz) 33834f9b3eeSRoland MainzCAT=( cat $bincat ) 33934f9b3eeSRoland MainzINS=( "" "builtin cat; " "builtin -d cat $bincat; " ": > /dev/null; " ) 34034f9b3eeSRoland MainzAPP=( "" "; :" ) 34134f9b3eeSRoland MainzTST=( 34234f9b3eeSRoland Mainz ( CMD='print foo | $cat' EXP=3 ) 34334f9b3eeSRoland Mainz ( CMD='$cat < $tmp/lin' ) 34434f9b3eeSRoland Mainz ( CMD='cat $tmp/lin | $cat' ) 34534f9b3eeSRoland Mainz ( CMD='read v < $tmp/buf; print $v' LIM=4*1024 ) 34634f9b3eeSRoland Mainz ( CMD='cat $tmp/buf | read v; print $v' LIM=4*1024 ) 34734f9b3eeSRoland Mainz) 34834f9b3eeSRoland Mainz 349*b30d1939SAndy Fiddamanif cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null 35034f9b3eeSRoland Mainzthen T=${#TST[@]} 35134f9b3eeSRoland Mainz TST[T].CMD='$cat <(print foo)' 35234f9b3eeSRoland Mainz TST[T].EXP=3 35334f9b3eeSRoland Mainzfi 35434f9b3eeSRoland Mainz 35534f9b3eeSRoland Mainz# prime the two data files to 512 bytes each 35634f9b3eeSRoland Mainz# $tmp/lin has newlines every 16 bytes and $tmp/buf has no newlines 35734f9b3eeSRoland Mainz# the outer loop doubles the file size at top 35834f9b3eeSRoland Mainz 35934f9b3eeSRoland Mainzbuf=$'1234567890abcdef' 36034f9b3eeSRoland Mainzlin=$'\n1234567890abcde' 36134f9b3eeSRoland Mainzfor ((i=0; i<5; i++)) 36234f9b3eeSRoland Mainzdo buf=$buf$buf 36334f9b3eeSRoland Mainz lin=$lin$lin 36434f9b3eeSRoland Mainzdone 36534f9b3eeSRoland Mainzprint -n "$buf" > $tmp/buf 36634f9b3eeSRoland Mainzprint -n "$lin" > $tmp/lin 36734f9b3eeSRoland Mainz 36834f9b3eeSRoland Mainzunset SKIP 36934f9b3eeSRoland Mainzfor ((n=1024; n<=1024*1024; n*=2)) 37034f9b3eeSRoland Mainzdo cat $tmp/buf $tmp/buf > $tmp/tmp 37134f9b3eeSRoland Mainz mv $tmp/tmp $tmp/buf 37234f9b3eeSRoland Mainz cat $tmp/lin $tmp/lin > $tmp/tmp 37334f9b3eeSRoland Mainz mv $tmp/tmp $tmp/lin 37434f9b3eeSRoland Mainz for ((S=0; S<${#SUB[@]}; S++)) 37534f9b3eeSRoland Mainz do for ((C=0; C<${#CAT[@]}; C++)) 37634f9b3eeSRoland Mainz do cat=${CAT[C]} 37734f9b3eeSRoland Mainz for ((I=0; I<${#INS[@]}; I++)) 37834f9b3eeSRoland Mainz do for ((A=0; A<${#APP[@]}; A++)) 37934f9b3eeSRoland Mainz do for ((T=0; T<${#TST[@]}; T++)) 38034f9b3eeSRoland Mainz do #undent...# 38134f9b3eeSRoland Mainz 38234f9b3eeSRoland Mainz if [[ ! ${SKIP[S][C][I][A][T]} ]] 38334f9b3eeSRoland Mainz then eval "{ x=${SUB[S].BEG}${INS[I]}${TST[T].CMD}${APP[A]}${SUB[S].END}; print \${#x}; } >\$tmp/out &" 38434f9b3eeSRoland Mainz m=$! 38534f9b3eeSRoland Mainz { sleep 4; kill -9 $m; } & 38634f9b3eeSRoland Mainz k=$! 38734f9b3eeSRoland Mainz wait $m 38834f9b3eeSRoland Mainz h=$? 38934f9b3eeSRoland Mainz kill -9 $k 39034f9b3eeSRoland Mainz wait $k 39134f9b3eeSRoland Mainz got=$(<$tmp/out) 39234f9b3eeSRoland Mainz if [[ ! $got ]] && (( h )) 39334f9b3eeSRoland Mainz then got=HUNG 39434f9b3eeSRoland Mainz fi 39534f9b3eeSRoland Mainz if [[ ${TST[T].EXP} ]] 39634f9b3eeSRoland Mainz then exp=${TST[T].EXP} 39734f9b3eeSRoland Mainz else exp=$n 39834f9b3eeSRoland Mainz fi 39934f9b3eeSRoland Mainz if [[ $got != $exp ]] 40034f9b3eeSRoland Mainz then # on failure skip similar tests on larger files sizes # 40134f9b3eeSRoland Mainz SKIP[S][C][I][A][T]=1 40234f9b3eeSRoland Mainz siz=$(printf $'%#i' $exp) 40334f9b3eeSRoland Mainz cmd=${TST[T].CMD//\$cat/$cat} 40434f9b3eeSRoland Mainz cmd=${cmd//\$tmp\/buf/$siz.buf} 40534f9b3eeSRoland Mainz cmd=${cmd//\$tmp\/lin/$siz.lin} 40634f9b3eeSRoland Mainz err_exit "'x=${SUB[S].BEG}${INS[I]}${cmd}${APP[A]}${SUB[S].END} && print \${#x}' failed -- expected '$exp', got '$got'" 40734f9b3eeSRoland Mainz elif [[ ${TST[T].EXP} ]] || (( TST[T].LIM >= n )) 40834f9b3eeSRoland Mainz then SKIP[S][C][I][A][T]=1 40934f9b3eeSRoland Mainz fi 41034f9b3eeSRoland Mainz fi 41134f9b3eeSRoland Mainz 41234f9b3eeSRoland Mainz #...indent# 41334f9b3eeSRoland Mainz done 41434f9b3eeSRoland Mainz done 41534f9b3eeSRoland Mainz done 41634f9b3eeSRoland Mainz done 41734f9b3eeSRoland Mainz done 41834f9b3eeSRoland Mainzdone 41934f9b3eeSRoland Mainz 42034f9b3eeSRoland Mainz# specifics -- there's more? 42134f9b3eeSRoland Mainz 42234f9b3eeSRoland Mainz{ 42334f9b3eeSRoland Mainz cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &' 42434f9b3eeSRoland Mainz eval $cmd 42534f9b3eeSRoland Mainz m=$! 42634f9b3eeSRoland Mainz { sleep 4; kill -9 $m; } & 42734f9b3eeSRoland Mainz k=$! 42834f9b3eeSRoland Mainz wait $m 42934f9b3eeSRoland Mainz h=$? 43034f9b3eeSRoland Mainz kill -9 $k 43134f9b3eeSRoland Mainz wait $k 43234f9b3eeSRoland Mainz got=$(<$tmp/out) 43334f9b3eeSRoland Mainz} 2>/dev/null 43434f9b3eeSRoland Mainzexp='' 43534f9b3eeSRoland Mainzif [[ ! $got ]] && (( h )) 43634f9b3eeSRoland Mainzthen got=HUNG 43734f9b3eeSRoland Mainzfi 43834f9b3eeSRoland Mainzif [[ $got != $exp ]] 43934f9b3eeSRoland Mainzthen err_exit "eval '$cmd' failed -- expected '$exp', got '$got'" 44034f9b3eeSRoland Mainzfi 44134f9b3eeSRoland Mainz 44234f9b3eeSRoland Mainzfloat t1=$SECONDS 44334f9b3eeSRoland Mainzsleep=$(whence -p sleep) 44434f9b3eeSRoland Mainzif [[ $sleep ]] 44534f9b3eeSRoland Mainzthen 44634f9b3eeSRoland Mainz $SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat 44734f9b3eeSRoland Mainz (( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging' 44834f9b3eeSRoland Mainz ((t1=SECONDS)) 44934f9b3eeSRoland Mainzfi 45034f9b3eeSRoland Mainz$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat 45134f9b3eeSRoland Mainz(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging' 45234f9b3eeSRoland Mainz 4533e14f97fSRoger A. Faulknerexp=HOME=$HOME 4543e14f97fSRoger A. Faulkner( HOME=/bin/sh ) 4553e14f97fSRoger A. Faulknergot=$(env | grep ^HOME=) 4563e14f97fSRoger A. Faulkner[[ $got == "$exp" ]] || err_exit "( HOME=/bin/sh ) cleanup failed -- expected '$exp', got '$got'" 4573e14f97fSRoger A. Faulkner 4583e14f97fSRoger A. Faulknercmd='echo $((case x in x)echo ok;esac);:)' 4593e14f97fSRoger A. Faulknerexp=ok 4603e14f97fSRoger A. Faulknergot=$($SHELL -c "$cmd" 2>&1) 4613e14f97fSRoger A. Faulkner[[ $got == "$exp" ]] || err_exit "'$cmd' failed -- expected '$exp', got '$got'" 4623e14f97fSRoger A. Faulkner 4633e14f97fSRoger A. Faulknercmd='eval "for i in 1 2; do eval /bin/echo x; done"' 4643e14f97fSRoger A. Faulknerexp=$'x\nx' 4653e14f97fSRoger A. Faulknergot=$($SHELL -c "$cmd") 4663e14f97fSRoger A. Faulknerif [[ $got != "$exp" ]] 4673e14f97fSRoger A. Faulknerthen EXP=$(printf %q "$exp") 4683e14f97fSRoger A. Faulkner GOT=$(printf %q "$got") 4693e14f97fSRoger A. Faulkner err_exit "'$cmd' failed -- expected $EXP, got $GOT" 4703e14f97fSRoger A. Faulknerfi 4713e14f97fSRoger A. Faulkner 472*b30d1939SAndy Fiddaman( 473*b30d1939SAndy Fiddaman$SHELL -c 'sleep 20 & pid=$!; { x=$( ( seq 60000 ) );kill -9 $pid;}&;wait $pid' 474*b30d1939SAndy Fiddaman) 2> /dev/null 475*b30d1939SAndy Fiddaman(( $? )) || err_exit 'nested command substitution with large output hangs' 476*b30d1939SAndy Fiddaman 477*b30d1939SAndy Fiddaman(.sh.foo=foobar) 478*b30d1939SAndy Fiddaman[[ ${.sh.foo} == foobar ]] && err_exit '.sh subvariables in subshells remain set' 479*b30d1939SAndy Fiddaman[[ $($SHELL -c 'print 1 | : "$(/bin/cat <(/bin/cat))"') ]] && err_exit 'process substitution not working correctly in subshells' 480*b30d1939SAndy Fiddaman 481*b30d1939SAndy Fiddaman# config hang bug 482*b30d1939SAndy Fiddamaninteger i 483*b30d1939SAndy Fiddamanfor ((i=1; i < 1000; i++)) 484*b30d1939SAndy Fiddamando typeset foo$i=$i 485*b30d1939SAndy Fiddamandone 486*b30d1939SAndy Fiddaman{ 487*b30d1939SAndy Fiddaman : $( (ac_space=' '; set | grep ac_space) 2>&1) 488*b30d1939SAndy Fiddaman} < /dev/null | cat > /dev/null & 489*b30d1939SAndy Fiddamansleep 1.5 490*b30d1939SAndy Fiddamanif kill -KILL $! 2> /dev/null 491*b30d1939SAndy Fiddamanthen err_exit 'process timed out with hung comsub' 492*b30d1939SAndy Fiddamanfi 493*b30d1939SAndy Fiddamanwait $! 2> /dev/null 494*b30d1939SAndy Fiddaman(( $? > 128 )) && err_exit 'incorrect exit status with comsub' 495*b30d1939SAndy Fiddaman 496*b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c '[[ ${ print foo },${ print bar } == foo,bar ]]' || err_exit '${ print foo },${ print bar } not working' 497*b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c '[[ ${ print foo; },${ print bar } == foo,bar ]]' || err_exit '${ print foo; },${ print bar } not working' 498*b30d1939SAndy Fiddaman 499*b30d1939SAndy Fiddamansrc=$'true 2>&1\n: $(true | true)\n: $(true | true)\n: $(true | true)\n'$(whence -p true) 500*b30d1939SAndy Fiddamanexp=ok 501*b30d1939SAndy Fiddamangot=$( $SHELL -c "(eval '$src'); echo $exp" ) 502*b30d1939SAndy Fiddaman[[ $got == "$exp" ]] || err_exit 'subshell eval of pipeline clobbers stdout' 503*b30d1939SAndy Fiddaman 504*b30d1939SAndy Fiddamanx=$( { time $SHELL -c date >| /dev/null;} 2>&1) 505*b30d1939SAndy Fiddaman[[ $x == *real*user*sys* ]] || err_exit 'time { ...;} 2>&1 in $(...) fails' 506*b30d1939SAndy Fiddaman 507*b30d1939SAndy Fiddamanx=$($SHELL -c '( function fx { export X=123; } ; fx; ); echo $X') 508*b30d1939SAndy Fiddaman[[ $x == 123 ]] && err_exit 'global variables set from with functions inside a 509*b30d1939SAndy Fiddamansubshell can leave side effects in parent shell' 510*b30d1939SAndy Fiddaman 511*b30d1939SAndy Fiddamandate=$(whence -p date) 512*b30d1939SAndy Fiddamanerr() { return $1; } 513*b30d1939SAndy Fiddaman( err 12 ) & pid=$! 514*b30d1939SAndy Fiddaman: $( $date) 515*b30d1939SAndy Fiddamanwait $pid 516*b30d1939SAndy Fiddaman[[ $? == 12 ]] || err_exit 'exit status from subshells not being preserved' 517*b30d1939SAndy Fiddaman 518*b30d1939SAndy Fiddamanif cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null 519*b30d1939SAndy Fiddamanthen x="$(sed 's/^/Hello /' <(print "Fred" | sort))" 520*b30d1939SAndy Fiddaman [[ $x == 'Hello Fred' ]] || err_exit "process substitution of pipeline in command substitution not working" 521*b30d1939SAndy Fiddamanfi 522*b30d1939SAndy Fiddaman 523*b30d1939SAndy Fiddaman{ 524*b30d1939SAndy Fiddaman$SHELL <<- \EOF 525*b30d1939SAndy Fiddaman function foo 526*b30d1939SAndy Fiddaman { 527*b30d1939SAndy Fiddaman integer i 528*b30d1939SAndy Fiddaman print -u2 foobar 529*b30d1939SAndy Fiddaman for ((i=0; i < 8000; i++)) 530*b30d1939SAndy Fiddaman do print abcdefghijk 531*b30d1939SAndy Fiddaman done 532*b30d1939SAndy Fiddaman print -u2 done 533*b30d1939SAndy Fiddaman } 534*b30d1939SAndy Fiddaman out=$(eval "foo | cat" 2>&1) 535*b30d1939SAndy Fiddaman (( ${#out} == 96011 )) || err_exit "\${#out} is ${#out} should be 96011" 536*b30d1939SAndy FiddamanEOF 537*b30d1939SAndy Fiddaman} & pid=$! 538*b30d1939SAndy Fiddaman$SHELL -c "{ sleep 4 && kill $pid ;}" 2> /dev/null 539*b30d1939SAndy Fiddaman(( $? == 0 )) && err_exit 'process has hung' 540*b30d1939SAndy Fiddaman 541*b30d1939SAndy Fiddaman{ 542*b30d1939SAndy Fiddamanx=$( $SHELL <<- \EOF 543*b30d1939SAndy Fiddaman function func1 { typeset IFS; : $(func2); print END ;} 544*b30d1939SAndy Fiddaman function func2 { IFS="BAR"; } 545*b30d1939SAndy Fiddaman func1 546*b30d1939SAndy Fiddaman func1 547*b30d1939SAndy FiddamanEOF 548*b30d1939SAndy Fiddaman) 549*b30d1939SAndy Fiddaman} 2> /dev/null 550*b30d1939SAndy Fiddaman[[ $x == $'END\nEND' ]] || err_exit 'bug in save/restore of IFS in subshell' 551*b30d1939SAndy Fiddaman 552*b30d1939SAndy Fiddamantrue=$(whence -p true) 553*b30d1939SAndy Fiddamandate=$(whence -p date) 554*b30d1939SAndy Fiddamantmpf=$tmp/foo 555*b30d1939SAndy Fiddamanfunction fun1 556*b30d1939SAndy Fiddaman{ 557*b30d1939SAndy Fiddaman $true 558*b30d1939SAndy Fiddaman cd - >/dev/null 2>&1 559*b30d1939SAndy Fiddaman print -u2 -- "$($date) SUCCESS" 560*b30d1939SAndy Fiddaman} 561*b30d1939SAndy Fiddaman 562*b30d1939SAndy Fiddamanprint -n $(fun1 2> $tmpf) 563*b30d1939SAndy Fiddaman[[ $(< $tmpf) == *SUCCESS ]] || err_exit 'standard error output lost with command substitution' 564*b30d1939SAndy Fiddaman 565*b30d1939SAndy Fiddaman 566*b30d1939SAndy Fiddamantmpfile=$tmp/foo 567*b30d1939SAndy Fiddamancat > $tmpfile <<-\EOF 568*b30d1939SAndy Fiddaman $SHELL -c 'function g { IFS= ;};function f { typeset IFS;(g);: $V;};f;f' 569*b30d1939SAndy Fiddaman EOF 570*b30d1939SAndy Fiddaman$SHELL 2> /dev/null "$tmpfile" || err_exit 'IFS in subshell causes core dump' 571*b30d1939SAndy Fiddaman 572*b30d1939SAndy Fiddamanunset i 573*b30d1939SAndy Fiddamanif [[ -d /dev/fd ]] 574*b30d1939SAndy Fiddamanthen integer i 575*b30d1939SAndy Fiddaman for ((i=11; i < 29; i++)) 576*b30d1939SAndy Fiddaman do if ! [[ -r /dev/fd/$i || -w /dev/fd/$i ]] 577*b30d1939SAndy Fiddaman then a=$($SHELL -c "[[ -r /dev/fd/$i || -w /dev/fd/$i ]]") 578*b30d1939SAndy Fiddaman (( $? )) || err_exit "file descriptor $i not close on exec" 579*b30d1939SAndy Fiddaman fi 580*b30d1939SAndy Fiddaman done 581*b30d1939SAndy Fiddamanfi 582*b30d1939SAndy Fiddaman 583*b30d1939SAndy Fiddamantrap USR1 USR1 584*b30d1939SAndy Fiddamantrap ERR ERR 585*b30d1939SAndy Fiddaman[[ $(trap -p USR1) == USR1 ]] || err_exit 'trap -p USR1 in subshell not working' 586*b30d1939SAndy Fiddaman[[ $(trap -p ERR) == ERR ]] || err_exit 'trap -p ERR in subshell not working' 587*b30d1939SAndy Fiddaman[[ $(trap -p) == *USR* ]] || err_exit 'trap -p in subshell does not contain USR' 588*b30d1939SAndy Fiddaman[[ $(trap -p) == *ERR* ]] || err_exit 'trap -p in subshell does not contain ERR' 589*b30d1939SAndy Fiddamantrap - USR1 ERR 590*b30d1939SAndy Fiddaman 591*b30d1939SAndy Fiddaman( PATH=/bin:/usr/bin 592*b30d1939SAndy Fiddamandot=$(cat <<-EOF 593*b30d1939SAndy Fiddaman $(ls -d .) 594*b30d1939SAndy Fiddaman EOF 595*b30d1939SAndy Fiddaman) ) & sleep 1 596*b30d1939SAndy Fiddamanif kill -0 $! 2> /dev/null 597*b30d1939SAndy Fiddamanthen err_exit 'command substitution containg here-doc with command substitution fails' 598*b30d1939SAndy Fiddamanfi 599*b30d1939SAndy Fiddaman 600*b30d1939SAndy Fiddamanprintf=$(whence -p printf) 601*b30d1939SAndy Fiddaman[[ $( { trap "echo foobar" EXIT; ( $printf ""); } & wait) == foobar ]] || err_exit 'exit trap not being invoked' 602*b30d1939SAndy Fiddaman 603*b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c '( PATH=/bin; set -o restricted) ; exit 0' || err_exit 'restoring PATH when a subshell enables restricted exits not working' 604*b30d1939SAndy Fiddaman 605*b30d1939SAndy Fiddaman$SHELL <<- \EOF 606*b30d1939SAndy Fiddaman wc=$(whence wc) head=$(whence head) 607*b30d1939SAndy Fiddaman print > /dev/null $( ( $head -c 1 /dev/zero | ( $wc -c) 3>&1 ) 3>&1) & 608*b30d1939SAndy Fiddaman pid=$! 609*b30d1939SAndy Fiddaman sleep 2 610*b30d1939SAndy Fiddaman kill -9 $! 2> /dev/null && err_exit '/dev/zero in command substitution hangs' 611*b30d1939SAndy Fiddaman wait $! 612*b30d1939SAndy FiddamanEOF 613*b30d1939SAndy Fiddaman 614*b30d1939SAndy Fiddamanfor f in /dev/stdout /dev/fd/1 615*b30d1939SAndy Fiddamando if [[ -e $f ]] 616*b30d1939SAndy Fiddaman then $SHELL -c "x=\$(command -p tee $f </dev/null 2>/dev/null)" || err_exit "$f in command substitution fails" 617*b30d1939SAndy Fiddaman fi 618*b30d1939SAndy Fiddamandone 619*b30d1939SAndy Fiddaman 620*b30d1939SAndy Fiddaman# ======================================== 621*b30d1939SAndy Fiddaman# Test that closing file descriptors don't affect capturing the output of a 622*b30d1939SAndy Fiddaman# subshell. Regression test for issue #198. 623*b30d1939SAndy Fiddamantmpfile=$(mktemp) 624*b30d1939SAndy Fiddamanexpected='return value' 625*b30d1939SAndy Fiddaman 626*b30d1939SAndy Fiddamanfunction get_value { 627*b30d1939SAndy Fiddaman case=$1 628*b30d1939SAndy Fiddaman (( case >= 1 )) && exec 3< $tmpfile 629*b30d1939SAndy Fiddaman (( case >= 2 )) && exec 4< $tmpfile 630*b30d1939SAndy Fiddaman (( case >= 3 )) && exec 6< $tmpfile 631*b30d1939SAndy Fiddaman 632*b30d1939SAndy Fiddaman # To trigger the bug we have to spawn an external command. Why is a 633*b30d1939SAndy Fiddaman # mystery but not really relevant. 634*b30d1939SAndy Fiddaman $(whence -p true) 635*b30d1939SAndy Fiddaman 636*b30d1939SAndy Fiddaman (( case >= 1 )) && exec 3<&- 637*b30d1939SAndy Fiddaman (( case >= 2 )) && exec 4<&- 638*b30d1939SAndy Fiddaman (( case >= 3 )) && exec 6<&- 639*b30d1939SAndy Fiddaman 640*b30d1939SAndy Fiddaman print $expected 641*b30d1939SAndy Fiddaman} 642*b30d1939SAndy Fiddaman 643*b30d1939SAndy Fiddamanactual=$(get_value 0) 644*b30d1939SAndy Fiddamanif [[ $actual != $expected ]] 645*b30d1939SAndy Fiddamanthen 646*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 0" 647*b30d1939SAndy Fiddamanfi 648*b30d1939SAndy Fiddaman 649*b30d1939SAndy Fiddamanactual=$(get_value 1) 650*b30d1939SAndy Fiddamanif [[ $actual != $expected ]] 651*b30d1939SAndy Fiddamanthen 652*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 1" 653*b30d1939SAndy Fiddamanfi 654*b30d1939SAndy Fiddaman 655*b30d1939SAndy Fiddamanactual=$(get_value 2) 656*b30d1939SAndy Fiddamanif [[ $actual != $expected ]] 657*b30d1939SAndy Fiddamanthen 658*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 2" 659*b30d1939SAndy Fiddamanfi 660*b30d1939SAndy Fiddaman 661*b30d1939SAndy Fiddamanactual=$(get_value 3) 662*b30d1939SAndy Fiddamanif [[ $actual != $expected ]] 663*b30d1939SAndy Fiddamanthen 664*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 3" 665*b30d1939SAndy Fiddamanfi 666*b30d1939SAndy Fiddaman 667*b30d1939SAndy Fiddamanrm $tmpfile 668*b30d1939SAndy Fiddaman 669*b30d1939SAndy Fiddamanexit $((Errors<125?Errors:125)) 670