1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 1982-2010 AT&T Intellectual Property # 5# and is licensed under the # 6# Common Public License, Version 1.0 # 7# by AT&T Intellectual Property # 8# # 9# A copy of the License is available at # 10# http://www.opensource.org/licenses/cpl1.0.txt # 11# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # 12# # 13# Information and Software Systems Research # 14# AT&T Research # 15# Florham Park NJ # 16# # 17# David Korn <dgk@research.att.com> # 18# # 19######################################################################## 20function err_exit 21{ 22 print -u2 -n "\t" 23 print -u2 -r ${Command}[$1]: "${@:2}" 24 let Errors+=1 25} 26alias err_exit='err_exit $LINENO' 27 28Command=${0##*/} 29integer Errors=0 30 31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } 32trap "cd /; rm -rf $tmp" EXIT 33 34# test basic file operations like redirection, pipes, file expansion 35set -- \ 36 go+r 0000 \ 37 go-r 0044 \ 38 ug=r 0330 \ 39 go+w 0000 \ 40 go-w 0022 \ 41 ug=w 0550 \ 42 go+x 0000 \ 43 go-x 0011 \ 44 ug=x 0660 \ 45 go-rx 0055 \ 46 uo-wx 0303 \ 47 ug-rw 0660 \ 48 o= 0007 49while (( $# >= 2 )) 50do umask 0 51 umask $1 52 g=$(umask) 53 [[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g" 54 shift 2 55done 56umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" 57if [[ $(umask -S) != u=rwx,g=rx,o=rx ]] 58then err_exit 'umask -S incorrect' 59fi 60pwd=$PWD 61[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL 62cd $tmp || { err_exit "cd $tmp failed"; exit 1; } 63um=$(umask -S) 64( umask 0777; > foobar ) 65rm -f foobar 66> foobar 67[[ -r foobar ]] || err_exit 'umask not being restored after subshell' 68umask "$um" 69rm -f foobar 70# optimizer bug test 71> foobar 72for i in 1 2 73do print foobar* 74 rm -f foobar 75done > out 76if [[ "$(<out)" != "foobar"$'\n'"foobar*" ]] 77then print -u2 "optimizer bug with file expansion" 78fi 79rm -f out foobar 80mkdir dir 81if [[ $(print */) != dir/ ]] 82then err_exit 'file expansion with trailing / not working' 83fi 84if [[ $(print *) != dir ]] 85then err_exit 'file expansion with single file not working' 86fi 87print hi > .foo 88if [[ $(print *) != dir ]] 89then err_exit 'file expansion leading . not working' 90fi 91date > dat1 || err_exit "date > dat1 failed" 92test -r dat1 || err_exit "dat1 is not readable" 93x=dat1 94cat <$x > dat2 || err_exit "cat < $x > dat2 failed" 95cat dat1 dat2 | cat | cat | cat > dat3 || err_exit "cat pipe failed" 96cat > dat4 <<! 97$(date) 98! 99cat dat1 dat2 | cat | cat | cat > dat5 & 100wait $! 101set -- dat* 102if (( $# != 5 )) 103then err_exit "dat* matches only $# files" 104fi 105if (command > foo\\abc) 2> /dev/null 106then set -- foo* 107 if [[ $1 != 'foo\abc' ]] 108 then err_exit 'foo* does not match foo\abc' 109 fi 110fi 111if ( : > TT* && : > TTfoo ) 2>/dev/null 112then set -- TT* 113 if (( $# < 2 )) 114 then err_exit 'TT* not expanding when file TT* exists' 115 fi 116fi 117cd ~- || err_exit "cd back failed" 118cat > $tmp/script <<- ! 119 #! $SHELL 120 print -r -- \$0 121! 122chmod 755 $tmp/script 123if [[ $($tmp/script) != "$tmp/script" ]] 124then err_exit '$0 not correct for #! script' 125fi 126bar=foo 127eval foo=\$bar 128if [[ $foo != foo ]] 129then err_exit 'eval foo=\$bar not working' 130fi 131bar='foo=foo\ bar' 132eval $bar 133if [[ $foo != 'foo bar' ]] 134then err_exit 'eval foo=\$bar, with bar="foo\ bar" not working' 135fi 136cd /tmp 137cd ../../tmp || err_exit "cd ../../tmp failed" 138if [[ $PWD != /tmp ]] 139then err_exit 'cd ../../tmp is not /tmp' 140fi 141( sleep 2; cat <<! 142foobar 143! 144) | cat > $tmp/foobar & 145wait $! 146foobar=$( < $tmp/foobar) 147if [[ $foobar != foobar ]] 148then err_exit "$foobar is not foobar" 149fi 150{ 151 print foo 152 /bin/echo bar 153 print bam 154} > $tmp/foobar 155if [[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]] 156then err_exit "output file pointer not shared correctly" 157fi 158cat > $tmp/foobar <<\! 159 print foo 160 /bin/echo bar 161 print bam 162! 163chmod +x $tmp/foobar 164if [[ $($tmp/foobar) != $'foo\nbar\nbam' ]] 165then err_exit "script not working" 166fi 167if [[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]] 168then err_exit "script | cat not working" 169fi 170if [[ $( $tmp/foobar) != $'foo\nbar\nbam' ]] 171then err_exit "output file pointer not shared correctly" 172fi 173rm -f $tmp/foobar 174x=$( (print foo) ; (print bar) ) 175if [[ $x != $'foo\nbar' ]] 176then err_exit " ( (print foo);(print bar ) failed" 177fi 178x=$( (/bin/echo foo) ; (print bar) ) 179if [[ $x != $'foo\nbar' ]] 180then err_exit " ( (/bin/echo);(print bar ) failed" 181fi 182x=$( (/bin/echo foo) ; (/bin/echo bar) ) 183if [[ $x != $'foo\nbar' ]] 184then err_exit " ( (/bin/echo);(/bin/echo bar ) failed" 185fi 186cat > $tmp/script <<\! 187if [[ -p /dev/fd/0 ]] 188then builtin cat 189 cat - > /dev/null 190 [[ -p /dev/fd/0 ]] && print ok 191else print no 192fi 193! 194chmod +x $tmp/script 195case $( (print) | $tmp/script;:) in 196ok) ;; 197no) err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;; 198*) err_exit "builtin replaces standard input pipe" ;; 199esac 200print 'print $0' > $tmp/script 201print ". $tmp/script" > $tmp/scriptx 202chmod +x $tmp/scriptx 203if [[ $($tmp/scriptx) != $tmp/scriptx ]] 204then err_exit '$0 not correct for . script' 205fi 206cd $tmp || { err_exit "cd $tmp failed"; exit 1; } 207print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e 208chmod 755 a b c d e 209x=$(./a) 210if [[ $x != "hello there" ]] 211then err_exit "nested scripts failed" 212fi 213x=$( (./a) | cat) 214if [[ $x != "hello there" ]] 215then err_exit "scripts in subshells fail" 216fi 217cd ~- || err_exit "cd back failed" 218x=$( (/bin/echo foo) 2> /dev/null ) 219if [[ $x != foo ]] 220then err_exit "subshell in command substitution fails" 221fi 222exec 1>&- 223x=$(print hello) 224if [[ $x != hello ]] 225then err_exit "command subsitution with stdout closed failed" 226fi 227cd $pwd 228x=$(cat <<\! | $SHELL 229/bin/echo | /bin/cat 230/bin/echo hello 231! 232) 233if [[ $x != $'\n'hello ]] 234then err_exit "$SHELL not working when standard input is a pipe" 235fi 236x=$( (/bin/echo hello) 2> /dev/null ) 237if [[ $x != hello ]] 238then err_exit "subshell in command substitution with 1 closed fails" 239fi 240cat > $tmp/script <<- \! 241read line 2> /dev/null 242print done 243! 244if [[ $($SHELL $tmp/script <&-) != done ]] 245then err_exit "executing script with 0 closed fails" 246fi 247trap '' INT 248cat > $tmp/script <<- \! 249trap 'print bad' INT 250kill -s INT $$ 251print good 252! 253chmod +x $tmp/script 254if [[ $($SHELL $tmp/script) != good ]] 255then err_exit "traps ignored by parent not ignored" 256fi 257trap - INT 258cat > $tmp/script <<- \! 259read line 260/bin/cat 261! 262if [[ $($SHELL $tmp/script <<! 263one 264two 265! 266) != two ]] 267then err_exit "standard input not positioned correctly" 268fi 269word=$(print $'foo\nbar' | { read line; /bin/cat;}) 270if [[ $word != bar ]] 271then err_exit "pipe to { read line; /bin/cat;} not working" 272fi 273word=$(print $'foo\nbar' | ( read line; /bin/cat) ) 274if [[ $word != bar ]] 275then err_exit "pipe to ( read line; /bin/cat) not working" 276fi 277if [[ $(print x{a,b}y) != 'xay xby' ]] 278then err_exit 'brace expansion not working' 279fi 280if [[ $(for i in foo bar 281 do ( tgz=$(print $i) 282 print $tgz) 283 done) != $'foo\nbar' ]] 284then err_exit 'for loop subshell optimizer bug' 285fi 286unset a1 287optbug() 288{ 289 set -A a1 foo bar bam 290 integer i 291 for ((i=0; i < 3; i++)) 292 do 293 (( ${#a1[@]} < 2 )) && return 0 294 set -- "${a1[@]}" 295 shift 296 set -A a1 -- "$@" 297 done 298 return 1 299} 300optbug || err_exit 'array size optimzation bug' 301wait # not running --pipefail which would interfere with subsequent tests 302: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect) 303sleep 20 & 304pids=$! 305if [[ $(jobs -p) != $! ]] 306then err_exit 'jobs -p not reporting a background job' 307fi 308sleep 20 & 309pids="$pids $!" 310foo() 311{ 312 set -- $(jobs -p) 313 (( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected" 314} 315foo 316kill $pids 317 318[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working' 319[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored' 320[[ $($SHELL -c 'o=foobar; for x in foo bar; do (o=save);print $o;done' 2> /dev/null ) == $'foobar\nfoobar' ]] || err_exit 'for loop optimization subshell bug' 321command exec 3<> /dev/null 322if cat /dev/fd/3 >/dev/null 2>&1 323then [[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working' 324 [[ $($SHELL -c $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! 325 line0 326 line1 327 line2 328 !!! 329 wait 330 cat '$tmp/scriptx 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' 331 > $tmp/scriptx 332 [[ $($SHELL -c $' 333 for i in 1 334 do tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! 335 line0 336 line1 337 line2 338 !!! 339 done 340 wait 341 cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' 342 [[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] || 343 err_exit 'process substitution of compound commands not working' 344fi 345[[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]] || err_exit 'command -p not restricted' 346print cat > $tmp/scriptx 347chmod +x $tmp/scriptx 348[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' 349[[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure' 350[[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure' 351exec 3<&- 352if [[ -d /dev/fd && -w /dev/fd/3 ]] 353then [[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not working outside for or while loop" 354 $SHELL -c '[[ $(for i in 1;do cat <(print hello);done ) == hello ]]' 2> /dev/null|| err_exit "process substitution not working in for or while loop" 355fi 356exec 3> /dev/null 357print 'print foo "$@"' > $tmp/scriptx 358[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' 359print "#! $SHELL" > $tmp/scriptx 360print 'print -- $0' >> $tmp/scriptx 361chmod +x $tmp/scriptx 362[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit "\$0 is $0 instead of $tmp/scriptx" 363cat > $tmp/scriptx <<- \EOF 364 myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} 365 set -o pipefail 366 sleep 3 | myfilter 367EOF 368(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' 369exec 3<&- 370( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' 371$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' 372$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substitution not supported' 373 x=${ 374 print hello 375 } 376 [[ $x == hello ]] 377EOF 378$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substitution with side effects not supported ' 379 y=bye 380 x=${ 381 y=hello 382 print hello 383 } 384 [[ $y == $x ]] 385EOF 386$SHELL 2> /dev/null <<- \EOF || err_exit 'nested ${...} command substitution not supported' 387 x=${ 388 print ${ print hello;} $(print world) 389 } 390 [[ $x == 'hello world' ]] 391EOF 392$SHELL 2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }' 393 x=${ { print -n } ; print -n hello ; } ; print ' world' } 394 [[ $x == '}hello world' ]] 395EOF 396$SHELL 2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working' 397 f() 398 { 399 print foo 400 } 401 [[ ${ f;}bar == foobar ]] 402EOF 403 404unset foo 405[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' 406[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' 407[[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' 408[[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' 409unset foo 410foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false' 411expected=foreback 412got=$(print -n fore;(sleep 2;print back)&) 413[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'" 414 415binfalse=$(whence -p false) 416for false in false $binfalse 417do x=$($false) && err_exit "x=\$($false) should fail" 418 $($false) && err_exit "\$($false) should fail" 419 $($false) > /dev/null && err_exit "\$($false) > /dev/null should fail" 420done 421if env x-a=y >/dev/null 2>&1 422then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' 423fi 424float s=SECONDS 425sleep=$(whence -p sleep) 426for i in 1 2 427do print $i 428done | while read sec; do ( $sleep $sec; $sleep $sec) done 429(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast' 430s=SECONDS 431set -o pipefail 432for ((i=0; i < 30; i++)) 433do print hello 434 sleep .1 435done | $sleep 1 436(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe' 437[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered' 438var=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!) 439[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered' 440 441exp= 442got=$( 443 function fun 444 { 445 $binfalse && echo FAILED 446 } 447 : works if this line deleted : | 448 fun 449 : works if this line deleted : 450) 451[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'" 452got=$( 453 : works if this line deleted : | 454 { $binfalse && echo FAILED; } 455 : works if this line deleted : 456) 457[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'" 458 459got=$( 460 : works if this line deleted : | 461 ( $binfalse && echo FAILED ) 462 : works if this line deleted : 463) 464[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'" 465 466( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null || err_exit 'trap DEBUG fails' 467 468true=$(whence -p true) 469set -o pipefail 470float start=$SECONDS end 471for ((i=0; i < 2; i++)) 472do print foo 473 sleep 1.5 474done | { read; $true; end=$SECONDS ;} 475(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish" 476set +o pipefail 477(( (SECONDS-start) > 2 )) && err_exit "pipefail causing /bin/true to wait for other end of pipe" 478 479 480{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails" 481 482exit $((Errors)) 483