1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 1982-2009 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 34unset HISTFILE 35 36function fun 37{ 38 while command exec 3>&1 39 do break 40 done 2> /dev/null 41 print -u3 good 42} 43print 'read -r a;print -r -u$1 -- "$a"' > $tmp/mycat 44chmod 755 $tmp/mycat 45for ((i=3; i < 10; i++)) 46do 47 eval "a=\$(print foo | $tmp/mycat" $i $i'>&1 > /dev/null |cat)' 2> /dev/null 48 [[ $a == foo ]] || err_exit "bad file descriptor $i in comsub script" 49done 50exec 3> /dev/null 51[[ $(fun) == good ]] || err_exit 'file 3 closed before subshell completes' 52exec 3>&- 53cd $tmp || { err_exit "cd $tmp failed"; exit ; } 54print foo > file1 55print bar >> file1 56if [[ $(<file1) != $'foo\nbar' ]] 57then err_exit 'append (>>) not working' 58fi 59set -o noclobber 60exec 3<> file1 61read -u3 line 62exp=foo 63if [[ $line != $exp ]] 64then err_exit "read on <> fd failed -- expected '$exp', got '$line'" 65fi 66if ( 4> file1 ) 2> /dev/null 67then err_exit 'noclobber not causing exclusive open' 68fi 69set +o noclobber 70 71FDFS=( 72 ( dir=/proc/self/fd semantics='open' ) 73 ( dir=/proc/$$/fd semantics='open' ) 74 ( dir=/dev/fd semantics='open|dup' ) 75 ( dir=/dev/fd semantics='dup' ) 76) 77for ((fdfs=0; fdfs<${#FDFS[@]}-1; fdfs++)) 78do [[ -e ${FDFS[fdfs].dir} ]] && { command : > ${FDFS[fdfs].dir}/1; } 2>/dev/null && break 79done 80 81exec 3<> file1 82if command exec 4< ${FDFS[fdfs].dir}/3 83then read -u3 got 84 read -u4 got 85 exp='foo|bar' 86 case $got in 87 foo) semantics='open' ;; 88 bar) semantics='dup' ;; 89 *) semantics='failed' ;; 90 esac 91 [[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "'4< ${FDFS[fdfs].dir}/3' $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" 92fi 93 94# 2004-11-25 ancient /dev/fd/N redirection bug fix 95got=$( 96 { 97 print -n 1 98 print -n 2 > ${FDFS[fdfs].dir}/2 99 print -n 3 100 print -n 4 > ${FDFS[fdfs].dir}/2 101 } 2>&1 102) 103exp='1234|4' 104case $got in 1051234) semantics='dup' ;; 1064) semantics='open' ;; 107*) semantics='failed' ;; 108esac 109[[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "${FDFS[fdfs].dir}/N $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" 110 111cat > close0 <<\! 112exec 0<&- 113echo $(./close1) 114! 115print "echo abc" > close1 116chmod +x close0 close1 117x=$(./close0) 118if [[ $x != "abc" ]] 119then err_exit "picked up file descriptor zero for opening script file" 120fi 121cat > close0 <<\! 122 for ((i=0; i < 1100; i++)) 123 do exec 4< /dev/null 124 read -u4 125 done 126 exit 0 127! 128./close0 2> /dev/null || err_exit "multiple exec 4< /dev/null can fail" 129$SHELL -c ' 130 trap "rm -f in out" EXIT 131 for ((i = 0; i < 1000; i++)) 132 do print -r -- "This is a test" 133 done > in 134 > out 135 exec 1<> out 136 builtin cat 137 print -r -- "$(<in)" 138 cmp -s in out' 2> /dev/null 139[[ $? == 0 ]] || err_exit 'builtin cat truncates files' 140cat >| script <<-\! 141print hello 142( exec 3<&- 4<&-) 143exec 3<&- 4<&- 144print world 145! 146chmod +x script 147[[ $( $SHELL ./script) == $'hello\nworld' ]] || err_exit 'closing 3 & 4 causes script to fail' 148cd ~- || err_exit "cd back failed" 149( exec > '' ) 2> /dev/null && err_exit '> "" does not fail' 150unset x 151( exec > ${x} ) 2> /dev/null && err_exit '> $x, where x null does not fail' 152exec <<! 153foo 154bar 155! 156( exec 0< /dev/null) 157read line 158if [[ $line != foo ]] 159then err_exit 'file descriptor not restored after exec in subshell' 160fi 161exec 3>&- 4>&- 162[[ $( { 163 read -r line;print -r -- "$line" 164 ( 165 read -r line;print -r -- "$line" 166 ) & wait 167 while read -r line 168 do print -r -- "$line" 169 done 170 } << ! 171line 1 172line 2 173line 3 174!) == $'line 1\nline 2\nline 3' ]] || err_exit 'read error with subshells' 175# 2004-05-11 bug fix 176cat > $tmp/1 <<- ++EOF++ 177 script=$tmp/2 178 trap "rm -f \$script" EXIT 179 exec 9> \$script 180 for ((i=3; i<9; i++)) 181 do eval "while read -u\$i; do : ;done \$i</dev/null" 182 print -u9 "exec \$i< /dev/null" 183 done 184 for ((i=0; i < 60; i++)) 185 do print -u9 -f "%.80c\n" ' ' 186 done 187 print -u9 'print ok' 188 exec 9<&- 189 chmod +x \$script 190 \$script 191++EOF++ 192chmod +x $tmp/1 193[[ $($SHELL $tmp/1) == ok ]] || err_exit "parent i/o causes child script to fail" 194# 2004-12-20 redirection loss bug fix 195cat > $tmp/1 <<- \++EOF++ 196 function a 197 { 198 trap 'print ok' EXIT 199 : > /dev/null 200 } 201 a 202++EOF++ 203chmod +x $tmp/1 204[[ $($tmp/1) == ok ]] || err_exit "trap on EXIT loses last command redirection" 205print > /dev/null {n}> $tmp/1 206[[ ! -s $tmp/1 ]] && newio=1 207if [[ $newio && $(print hello | while read -u$n; do print $REPLY; done {n}<&0) != hello ]] 208then err_exit "{n}<&0 not working with for loop" 209fi 210[[ $({ read -r;read -u3 3<&0; print -- "$REPLY" ;} <<! 211hello 212world 213!) == world ]] || err_exit 'I/O not synchronized with <&' 214x="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNSPQRSTUVWXYZ1234567890" 215for ((i=0; i < 62; i++)) 216do printf "%.39c\n" ${x:i:1} 217done > $tmp/seek 218if command exec 3<> $tmp/seek 219then (( $(3<#) == 0 )) || err_exit "not at position 0" 220 (( $(3<# ((EOF))) == 40*62 )) || err_exit "not at end-of-file" 221 command exec 3<# ((40*8)) || err_exit "absolute seek fails" 222 read -u3 223 [[ $REPLY == +(i) ]] || err_exit "expected iiii..., got $REPLY" 224 [[ $(3<#) == $(3<# ((CUR)) ) ]] || err_exit '$(3<#)!=$(3<#((CUR)))' 225 command exec 3<# ((CUR+80)) 226 read -u3 227 [[ $REPLY == {39}(l) ]] || err_exit "expected lll..., got $REPLY" 228 command exec 3<# ((EOF-80)) 229 read -u3 230 [[ $REPLY == +(9) ]] || err_exit "expected 999..., got $REPLY" 231 command exec 3># ((80)) 232 print -u3 -f "%.39c\n" @ 233 command exec 3># ((80)) 234 read -u3 235 [[ $REPLY == +(@) ]] || err_exit "expected @@@..., got $REPLY" 236 read -u3 237 [[ $REPLY == +(d) ]] || err_exit "expected ddd..., got $REPLY" 238 command exec 3># ((EOF)) 239 print -u3 -f "%.39c\n" ^ 240 (( $(3<# ((CUR-0))) == 40*63 )) || err_exit "not at extended end-of-file" 241 command exec 3<# ((40*62)) 242 read -u3 243 [[ $REPLY == +(^) ]] || err_exit "expected ddd..., got $REPLY" 244 command exec 3<# ((0)) 245 command exec 3<# *jjjj* 246 read -u3 247 [[ $REPLY == {39}(j) ]] || err_exit "<# pattern failed" 248 [[ $(command exec 3<## *llll*) = {39}(k) ]] || err_exit "<## pattern not saving standard output" 249 read -u3 250 [[ $REPLY == {39}(l) ]] || err_exit "<## pattern failed to position" 251 command exec 3<# *abc* 252 read -u3 && err_exit "not found pattern not positioning at eof" 253 cat $tmp/seek | read -r <# *WWW* 254 [[ $REPLY == *WWWWW* ]] || err_exit '<# not working for pipes' 255 { < $tmp/seek <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working' 256else err_exit "$tmp/seek: cannot open for reading" 257fi 258command exec 3<&- || 'cannot close 3' 259for ((i=0; i < 62; i++)) 260do printf "%.39c\n" ${x:i:1} 261done > $tmp/seek 262if command exec {n}<> $tmp/seek 263then { command exec {n}<#((EOF)) ;} 2> /dev/null || err_exit '{n}<# not working' 264 if $SHELL -c '{n}</dev/null' 2> /dev/null 265 then (( $({n}<#) == 40*62)) || err_exit '$({n}<#) not working' 266 else err_exit 'not able to parse {n}</dev/null' 267 fi 268fi 269$SHELL -ic ' 270{ 271 print -u2 || exit 2 272 print -u3 || exit 3 273 print -u4 || exit 4 274 print -u5 || exit 5 275 print -u6 || exit 6 276 print -u7 || exit 7 277 print -u8 || exit 8 278 print -u9 || exit 9 279} 3> /dev/null 4> /dev/null 5> /dev/null 6> /dev/null 7> /dev/null 8> /dev/null 9> /dev/null' > /dev/null 2>&1 280exitval=$? 281(( exitval )) && err_exit "print to unit $exitval failed" 282$SHELL -c "{ > $tmp/1 ; date;} >&- 2> /dev/null" > $tmp/2 283[[ -s $tmp/1 || -s $tmp/2 ]] && err_exit 'commands with standard output closed produce output' 284$SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard output not passed to subshell' 285[[ $(cat <<- \EOF | $SHELL 286 do_it_all() 287 { 288 dd 2>/dev/null # not a ksh93 buildin 289 return $? 290 } 291 do_it_all ; exit $? 292 hello world 293EOF) == 'hello world' ]] || err_exit 'invalid readahead on stdin' 294$SHELL -c 'exec 3>; /dev/null' 2> /dev/null && err_exit '>; with exec should be an error' 295$SHELL -c ': 3>; /dev/null' 2> /dev/null || err_exit '>; not working with at all' 296print hello > $tmp/1 297if ! $SHELL -c "false >; $tmp/1" 2> /dev/null 298then [[ $(<$tmp/1) == hello ]] || err_exit '>; not preserving file on failure' 299fi 300if ! $SHELL -c "sed -e 's/hello/hello world/' $tmp/1" >; $tmp/1 2> /dev/null 301then [[ $(<$tmp/1) == 'hello world' ]] || err_exit '>; not updating file on success' 302fi 303 304$SHELL -c 'exec 3<>; /dev/null' 2> /dev/null && err_exit '<>; with exec should be an error' 305$SHELL -c ': 3<>; /dev/null' 2> /dev/null || err_exit '<>; not working with at all' 306print $'hello\nworld' > $tmp/1 307if ! $SHELL -c "false <>; $tmp/1" 2> /dev/null 308then [[ $(<$tmp/1) == $'hello\nworld' ]] || err_exit '<>; not preserving file on failure' 309fi 310if ! $SHELL -c "head -1 $tmp/1" <>; $tmp/1 2> /dev/null 311then [[ $(<$tmp/1) == hello ]] || err_exit '<>; not truncating file on success of head' 312fi 313print $'hello\nworld' > $tmp/1 314if ! $SHELL -c head < $tmp/1 <#((6)) <>; $tmp/1 2> /dev/null 315then [[ $(<$tmp/1) == world ]] || err_exit '<>; not truncating file on success of behead' 316fi 317 318unset y 319read -n1 y <<! 320abc 321! 322if [[ $y != a ]] 323then err_exit 'read -n1 not working' 324fi 325unset a 326{ read -N3 a; read -N1 b;} <<! 327abcdefg 328! 329[[ $a == abc ]] || err_exit 'read -N3 here-document not working' 330[[ $b == d ]] || err_exit 'read -N1 here-document not working' 331read -n3 a <<! 332abcdefg 333! 334[[ $a == abc ]] || err_exit 'read -n3 here-document not working' 335(print -n a;sleep 1; print -n bcde) | { read -N3 a; read -N1 b;} 336[[ $a == abc ]] || err_exit 'read -N3 from pipe not working' 337[[ $b == d ]] || err_exit 'read -N1 from pipe not working' 338(print -n a;sleep 1; print -n bcde) |read -n3 a 339[[ $a == a ]] || err_exit 'read -n3 from pipe not working' 340if mkfifo $tmp/fifo 2> /dev/null 341then (print -n a; sleep 1;print -n bcde) > $tmp/fifo & 342 { 343 read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' 344 read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' 345 } 5< $tmp/fifo 346 [[ $a == a ]] || err_exit 'read -n3 from fifo not working' 347 rm -f $tmp/fifo 348 mkfifo $tmp/fifo 2> /dev/null 349 (print -n a; sleep 1;print -n bcde) > $tmp/fifo & 350 { 351 read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' 352 read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' 353 } 5< $tmp/fifo 354 [[ $a == abc ]] || err_exit 'read -N3 from fifo not working' 355 [[ $b == d ]] || err_exit 'read -N1 from fifo not working' 356fi 357( 358 print -n 'prompt1: ' 359 sleep .1 360 print line2 361 sleep .1 362 print -n 'prompt2: ' 363 sleep .1 364) | { 365 read -t2 -n 1000 line1 366 read -t2 -n 1000 line2 367 read -t2 -n 1000 line3 368 read -t2 -n 1000 line4 369} 370[[ $? == 0 ]] && err_exit 'should have time out' 371[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '" 372[[ $line2 == line2 ]] || err_exit "line2 should be line2" 373[[ $line3 == 'prompt2: ' ]] || err_exit "line3 should be 'prompt2: '" 374[[ ! $line4 ]] || err_exit "line4 should be empty" 375 376if $SHELL -c "export LC_ALL=en_US.UTF-8; c=$'\342\202\254'; [[ \${#c} == 1 ]]" 2>/dev/null 377then lc_utf8=en_US.UTF-8 378else lc_utf8='' 379fi 380 381typeset -a e o=(-n2 -N2) 382integer i 383set -- \ 384 'a' 'bcd' 'a bcd' 'ab cd' \ 385 'ab' 'cd' 'ab cd' 'ab cd' \ 386 'abc' 'd' 'ab cd' 'ab cd' \ 387 'abcd' '' 'ab cd' 'ab cd' 388while (( $# >= 3 )) 389do a=$1 390 b=$2 391 e[0]=$3 392 e[1]=$4 393 shift 4 394 for ((i = 0; i < 2; i++)) 395 do for lc_all in C $lc_utf8 396 do g=$(LC_ALL=$lc_all $SHELL -c "{ print -n '$a'; sleep 0.2; print -n '$b'; sleep 0.2; } | { read ${o[i]} a; print -n \$a; read a; print -n \ \$a; }") 397 [[ $g == "${e[i]}" ]] || err_exit "LC_ALL=$lc_all read ${o[i]} from pipe '$a $b' failed -- expected '${e[i]}', got '$g'" 398 done 399 done 400done 401 402if [[ $lc_utf8 ]] 403then export LC_ALL=en_US.UTF-8 404 typeset -a c=( '' 'A' $'\303\274' $'\342\202\254' ) 405 integer i w 406 typeset o 407 if (( ${#c[2]} == 1 && ${#c[3]} == 1 )) 408 then for i in 1 2 3 409 do for o in n N 410 do for w in 1 2 3 411 do print -nr "${c[w]}" | read -${o}${i} g 412 if [[ $o == N ]] && (( i > 1 )) 413 then e='' 414 else e=${c[w]} 415 fi 416 [[ $g == "$e" ]] || err_exit "read -${o}${i} failed for '${c[w]}' -- expected '$e', got '$g'" 417 done 418 done 419 done 420 fi 421fi 422 423exec 3<&2 424file=$tmp/file 425redirect 5>$file 2>&5 426print -u5 -f 'This is a test\n' 427print -u2 OK 428exec 2<&3 429exp=$'This is a test\nOK' 430got=$(< $file) 431[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")" 432print 'hello world' > $file 4331<>; $file 1># ((5)) 434(( $(wc -c < $file) == 5 )) || err_exit "$file was not truncate to 5 bytes" 435 436$SHELL -c "PS4=':2:' 437 exec 1> $tmp/21.out 2> $tmp/22.out 438 set -x 439 printf ':1:A:' 440 print \$(:) 441 print :1:Z:" 1> $tmp/11.out 2> $tmp/12.out 442[[ -s $tmp/11.out ]] && err_exit "standard output leaked past redirection" 443[[ -s $tmp/12.out ]] && err_exit "standard error leaked past redirection" 444exp=$':1:A:\n:1:Z:' 445got=$(<$tmp/21.out) 446[[ $exp == "$got" ]] || err_exit "standard output garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" 447exp=$':2:printf :1:A:\n:2::\n:2:print\n:2:print :1:Z:' 448got=$(<$tmp/22.out) 449[[ $exp == "$got" ]] || err_exit "standard error garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" 450 451exit $((Errors)) 452