1*4887Schin######################################################################## 2*4887Schin# # 3*4887Schin# This software is part of the ast package # 4*4887Schin# Copyright (c) 1982-2007 AT&T Knowledge Ventures # 5*4887Schin# and is licensed under the # 6*4887Schin# Common Public License, Version 1.0 # 7*4887Schin# by AT&T Knowledge Ventures # 8*4887Schin# # 9*4887Schin# A copy of the License is available at # 10*4887Schin# http://www.opensource.org/licenses/cpl1.0.txt # 11*4887Schin# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # 12*4887Schin# # 13*4887Schin# Information and Software Systems Research # 14*4887Schin# AT&T Research # 15*4887Schin# Florham Park NJ # 16*4887Schin# # 17*4887Schin# David Korn <dgk@research.att.com> # 18*4887Schin# # 19*4887Schin######################################################################## 20*4887Schinfunction err_exit 21*4887Schin{ 22*4887Schin print -u2 -n "\t" 23*4887Schin print -u2 -r ${Command}[$1]: "${@:2}" 24*4887Schin let Errors+=1 25*4887Schin} 26*4887Schinalias err_exit='err_exit $LINENO' 27*4887Schin 28*4887Schin# test shell builtin commands 29*4887SchinCommand=${0##*/} 30*4887Schininteger Errors=0 31*4887Schinbuiltin getconf 32*4887Schin: ${foo=bar} || err_exit ": failed" 33*4887Schin[[ $foo = bar ]] || err_exit ": side effects failed" 34*4887Schinset -- - foobar 35*4887Schin[[ $# = 2 && $1 = - && $2 = foobar ]] || err_exit "set -- - foobar failed" 36*4887Schinset -- -x foobar 37*4887Schin[[ $# = 2 && $1 = -x && $2 = foobar ]] || err_exit "set -- -x foobar failed" 38*4887Schingetopts :x: foo || err_exit "getopts :x: returns false" 39*4887Schin[[ $foo = x && $OPTARG = foobar ]] || err_exit "getopts :x: failed" 40*4887SchinOPTIND=1 41*4887Schingetopts :r:s var -r 42*4887Schinif [[ $var != : || $OPTARG != r ]] 43*4887Schinthen err_exit "'getopts :r:s var -r' not working" 44*4887Schinfi 45*4887SchinOPTIND=1 46*4887Schingetopts :d#u var -d 100 47*4887Schinif [[ $var != d || $OPTARG != 100 ]] 48*4887Schinthen err_exit "'getopts :d#u var -d 100' not working var=$var" 49*4887Schinfi 50*4887SchinOPTIND=1 51*4887Schinwhile getopts 'ab' option -a -b 52*4887Schindo [[ $OPTIND == $((OPTIND)) ]] || err_exit "OPTIND optimization bug" 53*4887Schindone 54*4887Schin 55*4887SchinUSAGE=$'[-][S:server?Operate on the specified \asubservice\a:]:[subservice:=pmserver] 56*4887Schin { 57*4887Schin [p:pmserver] 58*4887Schin [r:repserver] 59*4887Schin [11:notifyd] 60*4887Schin }' 61*4887Schinset pmser p rep r notifyd -11 62*4887Schinwhile (( $# > 1 )) 63*4887Schindo OPTIND=1 64*4887Schin getopts "$USAGE" OPT -S $1 65*4887Schin [[ $OPT == S && $OPTARG == $2 ]] || err_exit "OPT=$OPT OPTARG=$OPTARG -- expected OPT=S OPTARG=$2" 66*4887Schin shift 2 67*4887Schindone 68*4887Schin 69*4887Schinfalse ${foo=bar} && err_exit "false failed" 70*4887Schinread <<! 71*4887Schinhello world 72*4887Schin! 73*4887Schin[[ $REPLY = 'hello world' ]] || err_exit "read builtin failed" 74*4887Schinprint x:y | IFS=: read a b 75*4887Schinif [[ $a != x ]] 76*4887Schinthen err_exit "IFS=: read ... not working" 77*4887Schinfi 78*4887Schinread <<! 79*4887Schinhello \ 80*4887Schinworld 81*4887Schin! 82*4887Schin[[ $REPLY = 'hello world' ]] || err_exit "read continuation failed" 83*4887Schinread -d x <<! 84*4887Schinhello worldxfoobar 85*4887Schin! 86*4887Schin[[ $REPLY = 'hello world' ]] || err_exit "read builtin failed" 87*4887Schinread <<\! 88*4887Schinhello \ 89*4887Schin world \ 90*4887Schin 91*4887Schin! 92*4887Schin[[ $REPLY == 'hello world' ]] || err_exit "read continuation2 failed" 93*4887Schinprint "one\ntwo" | { read line 94*4887Schin print $line | /bin/cat > /dev/null 95*4887Schin read line 96*4887Schin} 97*4887Schinread <<\! 98*4887Schin\ 99*4887Schina\ 100*4887Schin\ 101*4887Schin\ 102*4887Schinb 103*4887Schin! 104*4887Schinif [[ $REPLY != ab ]] 105*4887Schinthen err_exit "read multiple continuation failed" 106*4887Schinfi 107*4887Schinif [[ $line != two ]] 108*4887Schinthen err_exit "read from pipeline failed" 109*4887Schinfi 110*4887Schinline=two 111*4887Schinread line < /dev/null 112*4887Schinif [[ $line != "" ]] 113*4887Schinthen err_exit "read from /dev/null failed" 114*4887Schinfi 115*4887Schinif [[ $(print -R -) != - ]] 116*4887Schinthen err_exit "print -R not working correctly" 117*4887Schinfi 118*4887Schinif [[ $(print -- -) != - ]] 119*4887Schinthen err_exit "print -- not working correctly" 120*4887Schinfi 121*4887Schinprint -f "hello%nbar\n" size > /dev/null 122*4887Schinif (( size != 5 )) 123*4887Schinthen err_exit "%n format of printf not working" 124*4887Schinfi 125*4887Schinprint -n -u2 2>&1- 126*4887Schin[[ -w /dev/fd/1 ]] || err_exit "2<&1- with built-ins has side effects" 127*4887Schinx=$0 128*4887Schinif [[ $(eval 'print $0') != $x ]] 129*4887Schinthen err_exit '$0 not correct for eval' 130*4887Schinfi 131*4887Schinunset x 132*4887Schinreadonly x 133*4887Schinset -- $(readonly) 134*4887Schinif [[ " $@ " != *" x "* ]] 135*4887Schinthen err_exit 'unset readonly variables are not displayed' 136*4887Schinfi 137*4887Schinif [[ $( for i in foo bar 138*4887Schin do print $i 139*4887Schin continue 10 140*4887Schin done 141*4887Schin ) != $'foo\nbar' ]] 142*4887Schinthen err_exit 'continue breaks out of loop' 143*4887Schinfi 144*4887Schin(continue bad 2>/dev/null && err_exit 'continue bad should return an error') 145*4887Schin(break bad 2>/dev/null && err_exit 'break bad should return an error') 146*4887Schin(continue 0 2>/dev/null && err_exit 'continue 0 should return an error') 147*4887Schin(break 0 2>/dev/null && err_exit 'break 0 should return an error') 148*4887Schinbreakfun() { break;} 149*4887Schincontinuefun() { continue;} 150*4887Schinfor fun in break continue 151*4887Schindo if [[ $( for i in foo 152*4887Schin do ${fun}fun 153*4887Schin print $i 154*4887Schin done 155*4887Schin ) != foo ]] 156*4887Schin then err_exit "$fun call in ${fun}fun breaks out of for loop" 157*4887Schin fi 158*4887Schindone 159*4887Schinif [[ $(print -f "%b" "\a\n\v\b\r\f\E\03\\oo") != $'\a\n\v\b\r\f\E\03\\oo' ]] 160*4887Schinthen err_exit 'print -f "%b" not working' 161*4887Schinfi 162*4887Schinif [[ $(print -f "%P" "[^x].*b$") != '*[!x]*b' ]] 163*4887Schinthen err_exit 'print -f "%P" not working' 164*4887Schinfi 165*4887Schinif [[ $(abc: for i in foo bar;do print $i;break abc;done) != foo ]] 166*4887Schinthen err_exit 'break labels not working' 167*4887Schinfi 168*4887Schinif [[ $(command -v if) != if ]] 169*4887Schinthen err_exit 'command -v not working' 170*4887Schinfi 171*4887Schinread -r var <<\! 172*4887Schin 173*4887Schin! 174*4887Schinif [[ $var != "" ]] 175*4887Schinthen err_exit "read -r of blank line not working" 176*4887Schinfi 177*4887Schinmkdir -p /tmp/ksh$$/a/b/c 2>/dev/null || err_exit "mkdir -p failed" 178*4887Schin$SHELL -c "cd /tmp/ksh$$/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails" 179*4887Schinrm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" 180*4887Schintrap 'print HUP' HUP 181*4887Schinif [[ $(trap) != "trap -- 'print HUP' HUP" ]] 182*4887Schinthen err_exit '$(trap) not working' 183*4887Schinfi 184*4887Schinif [[ $(trap -p HUP) != 'print HUP' ]] 185*4887Schinthen err_exit '$(trap -p HUP) not working' 186*4887Schinfi 187*4887Schin[[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok 188*4887Schin ]] || err_exit 'SIGTERM not recognized' 189*4887Schin[[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok 190*4887Schin ]] || err_exit 'SIGTERM not recognized' 191*4887Schin${SHELL} -c 'kill -1 -$$' 2> /dev/null 192*4887Schin[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' 193*4887Schin${SHELL} -c 'kill -1 -$$' 2> /dev/null 194*4887Schin[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working' 195*4887Schin${SHELL} -c 'kill -s HUP -$$' 2> /dev/null 196*4887Schin[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working' 197*4887Schinn=123 198*4887Schintypeset -A base 199*4887Schinbase[o]=8# 200*4887Schinbase[x]=16# 201*4887Schinbase[X]=16# 202*4887Schinfor i in d i o u x X 203*4887Schindo if (( $(( ${base[$i]}$(printf "%$i" $n) )) != n )) 204*4887Schin then err_exit "printf %$i not working" 205*4887Schin fi 206*4887Schindone 207*4887Schinif [[ $( trap 'print done' EXIT) != done ]] 208*4887Schinthen err_exit 'trap on EXIT not working' 209*4887Schinfi 210*4887Schinif [[ $( trap 'print done' EXIT; trap - EXIT) == done ]] 211*4887Schinthen err_exit 'trap on EXIT not being cleared' 212*4887Schinfi 213*4887Schinif [[ $(type test) != 'test is a shell builtin' ]] 214*4887Schinthen err_exit 'whence -v test not a builtin' 215*4887Schinfi 216*4887Schinbuiltin -d test 217*4887Schinif [[ $(type test) == *builtin* ]] 218*4887Schinthen err_exit 'whence -v test after builtin -d incorrect' 219*4887Schinfi 220*4887Schintypeset -Z3 percent=$(printf '%o\n' "'%'") 221*4887Schinforrmat=\\${percent}s 222*4887Schinif [[ $(printf "$forrmat") != %s ]] 223*4887Schinthen err_exit "printf $forrmat not working" 224*4887Schinfi 225*4887Schinif (( $(printf 'x\0y' | wc -c) != 3 )) 226*4887Schinthen err_exit 'printf \0 not working' 227*4887Schinfi 228*4887Schinif [[ $(printf "%bx%s\n" 'f\to\cbar') != $'f\to' ]] 229*4887Schinthen err_exit 'printf %bx%s\n not working' 230*4887Schinfi 231*4887Schinalpha=abcdefghijklmnop 232*4887Schinif [[ $(printf "%10.*s\n" 5 $alpha) != ' abcde' ]] 233*4887Schinthen err_exit 'printf %10.%s\n not working' 234*4887Schinfi 235*4887Schinfloat x2=.0000625 236*4887Schinif [[ $(printf "%10.5E\n" x2) != 6.25000E-05 ]] 237*4887Schinthen err_exit 'printf "%10.5E" not normalizing correctly' 238*4887Schinfi 239*4887Schinx2=.000000001 240*4887Schinif [[ $(printf "%g\n" x2 2>/dev/null) != 1e-09 ]] 241*4887Schinthen err_exit 'printf "%g" not working correctly' 242*4887Schinfi 243*4887Schin#FIXME#($SHELL read -s foobar <<\! 244*4887Schin#FIXME#testing 245*4887Schin#FIXME#! 246*4887Schin#FIXME#) 2> /dev/null || err_exit ksh read -s var fails 247*4887Schinif [[ $(printf +3 2>/dev/null) != +3 ]] 248*4887Schinthen err_exit 'printf is not processing formats beginning with + correctly' 249*4887Schinfi 250*4887Schinif printf "%d %d\n" 123bad 78 >/dev/null 2>/dev/null 251*4887Schinthen err_exit "printf not exiting non-zero with conversion errors" 252*4887Schinfi 253*4887Schinif [[ $(trap --version 2> /dev/null;print done) != done ]] 254*4887Schinthen err_exit 'trap builtin terminating after --version' 255*4887Schinfi 256*4887Schinif [[ $(set --version 2> /dev/null;print done) != done ]] 257*4887Schinthen err_exit 'set builtin terminating after --veresion' 258*4887Schinfi 259*4887Schinunset -f foobar 260*4887Schinfunction foobar 261*4887Schin{ 262*4887Schin print 'hello world' 263*4887Schin} 264*4887SchinOPTIND=1 265*4887Schinif [[ $(getopts $'[+?X\ffoobar\fX]' v --man 2>&1) != *'Xhello world'X* ]] 266*4887Schinthen err_exit '\f...\f not working in getopts usage strings' 267*4887Schinfi 268*4887Schinif [[ $(printf '%H\n' $'<>"& \'\tabc') != '<>"& '	abc' ]] 269*4887Schinthen err_exit 'printf %H not working' 270*4887Schinfi 271*4887Schinif [[ $(printf '%R %R %R %R\n' 'a.b' '*.c' '^' '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]] 272*4887Schinthen err_exit 'printf %R not working' 273*4887Schinfi 274*4887Schinif [[ $(printf '%..:c\n' abc) != a:b:c ]] 275*4887Schinthen err_exit "printf '%..:c' not working" 276*4887Schinfi 277*4887Schinif [[ $(printf '%..*c\n' : abc) != a:b:c ]] 278*4887Schinthen err_exit "printf '%..*c' not working" 279*4887Schinfi 280*4887Schinif [[ $(printf '%..:s\n' abc def ) != abc:def ]] 281*4887Schinthen err_exit "printf '%..:s' not working" 282*4887Schinfi 283*4887Schinif [[ $(printf '%..*s\n' : abc def) != abc:def ]] 284*4887Schinthen err_exit "printf '%..*s' not working" 285*4887Schinfi 286*4887Schin[[ $(printf '%q\n') == '' ]] || err_exit 'printf "%q" with missing arguments' 287*4887Schin# we won't get hit by the one second boundary twice, right? 288*4887Schin[[ $(printf '%T\n' now) == "$(date)" ]] || 289*4887Schin[[ $(printf '%T\n' now) == "$(date)" ]] || 290*4887Schinerr_exit 'printf "%T" now' 291*4887Schinbehead() 292*4887Schin{ 293*4887Schin read line 294*4887Schin left=$(cat) 295*4887Schin} 296*4887Schinprint $'line1\nline2' | behead 297*4887Schinif [[ $left != line2 ]] 298*4887Schinthen err_exit "read reading ahead on a pipe" 299*4887Schinfi 300*4887Schinread -n1 y <<! 301*4887Schinabc 302*4887Schin! 303*4887Schinif [[ $y != a ]] 304*4887Schinthen err_exit 'read -n1 not working' 305*4887Schinfi 306*4887Schinprint -n $'{ read -r line;print $line;}\nhello' > /tmp/ksh$$ 307*4887Schinchmod 755 /tmp/ksh$$ 308*4887Schintrap 'rm -rf /tmp/ksh$$' EXIT 309*4887Schinif [[ $($SHELL < /tmp/ksh$$) != hello ]] 310*4887Schinthen err_exit 'read of incomplete line not working correctly' 311*4887Schinfi 312*4887Schinset -f 313*4887Schinset -- * 314*4887Schinif [[ $1 != '*' ]] 315*4887Schinthen err_exit 'set -f not working' 316*4887Schinfi 317*4887Schinunset pid1 pid2 318*4887Schinfalse & 319*4887Schinpid1=$! 320*4887Schinpid2=$( 321*4887Schin wait $pid1 322*4887Schin (( $? == 127 )) || err_exit "job known to subshell" 323*4887Schin print $! 324*4887Schin) 325*4887Schinwait $pid1 326*4887Schin(( $? == 1 )) || err_exit "wait not saving exit value" 327*4887Schinwait $pid2 328*4887Schin(( $? == 127 )) || err_exit "subshell job known to parent" 329*4887Schinset --noglob 330*4887Schinifs=$IFS 331*4887SchinIFS=, 332*4887Schinset -- $(getconf LIBPATH) 333*4887SchinIFS=$ifs 334*4887Schinenv= 335*4887Schinfor v 336*4887Schindo IFS=: 337*4887Schin set -- $v 338*4887Schin IFS=$ifs 339*4887Schin eval [[ \$$2 ]] && env="$env $2=\"\$$2\"" 340*4887Schindone 341*4887Schinset --glob 342*4887Schinif [[ $(foo=bar; eval foo=\$foo $env exec -c \$SHELL -c \'print \$foo\') != bar ]] 343*4887Schinthen err_exit '"name=value exec -c ..." not working' 344*4887Schinfi 345*4887Schin$SHELL -c 'OPTIND=-1000000; getopts a opt -a' 2> /dev/null 346*4887Schin[[ $? == 1 ]] || err_exit 'getopts with negative OPTIND not working' 347*4887Schingetopts 'n#num' opt -n 3 348*4887Schin[[ $OPTARG == 3 ]] || err_exit 'getopts with numerical arguments failed' 349*4887Schinif [[ $($SHELL -c $'printf \'%2$s %1$s\n\' world hello') != 'hello world' ]] 350*4887Schinthen err_exit 'printf %2$s %1$s not working' 351*4887Schinfi 352*4887Schin((n=0)) 353*4887Schin((n++)); ARGC[$n]=1 ARGV[$n]="" 354*4887Schin((n++)); ARGC[$n]=2 ARGV[$n]="-a" 355*4887Schin((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2" 356*4887Schin((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2 x" 357*4887Schin((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2 x y" 358*4887Schinfor ((i=1; i<=n; i++)) 359*4887Schindo set -- ${ARGV[$i]} 360*4887Schin OPTIND=0 361*4887Schin while getopts -a tst "av:" OPT 362*4887Schin do : 363*4887Schin done 364*4887Schin if [[ $OPTIND != ${ARGC[$i]} ]] 365*4887Schin then err_exit "\$OPTIND after getopts loop incorrect -- got $OPTIND, expected ${ARGC[$i]}" 366*4887Schin fi 367*4887Schindone 368*4887Schinunset a 369*4887Schin{ read -N3 a; read -N1 b;} <<! 370*4887Schinabcdefg 371*4887Schin! 372*4887Schin[[ $a == abc ]] || err_exit 'read -N3 here-document not working' 373*4887Schin[[ $b == d ]] || err_exit 'read -N1 here-document not working' 374*4887Schinread -n3 a <<! 375*4887Schinabcdefg 376*4887Schin! 377*4887Schin[[ $a == abc ]] || err_exit 'read -n3 here-document not working' 378*4887Schin(print -n a;sleep 1; print -n bcde) | { read -N3 a; read -N1 b;} 379*4887Schin[[ $a == abc ]] || err_exit 'read -N3 from pipe not working' 380*4887Schin[[ $b == d ]] || err_exit 'read -N1 from pipe not working' 381*4887Schin(print -n a;sleep 1; print -n bcde) |read -n3 a 382*4887Schin[[ $a == a ]] || err_exit 'read -n3 from pipe not working' 383*4887Schinrm -f /tmp/fifo$$ 384*4887Schinif mkfifo /tmp/fifo$$ 2> /dev/null 385*4887Schinthen (print -n a; sleep 1;print -n bcde) > /tmp/fifo$$ & 386*4887Schin { 387*4887Schin read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' 388*4887Schin read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' 389*4887Schin } 5< /tmp/fifo$$ 390*4887Schin [[ $a == a ]] || err_exit 'read -n3 from fifo not working' 391*4887Schin rm -f /tmp/fifo$$ 392*4887Schin mkfifo /tmp/fifo$$ 2> /dev/null 393*4887Schin (print -n a; sleep 1;print -n bcde) > /tmp/fifo$$ & 394*4887Schin { 395*4887Schin read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' 396*4887Schin read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' 397*4887Schin } 5< /tmp/fifo$$ 398*4887Schin [[ $a == abc ]] || err_exit 'read -N3 from fifo not working' 399*4887Schin [[ $b == d ]] || err_exit 'read -N1 from fifo not working' 400*4887Schinfi 401*4887Schinrm -f /tmp/fifo$$ 402*4887Schinfunction longline 403*4887Schin{ 404*4887Schin integer i 405*4887Schin for((i=0; i < $1; i++)) 406*4887Schin do print argument$i 407*4887Schin done 408*4887Schin} 409*4887Schin# test command -x option 410*4887Schininteger sum=0 n=10000 411*4887Schinif ! ${SHELL:-ksh} -c 'print $#' count $(longline $n) > /dev/null 2>&1 412*4887Schinthen for i in $(command command -x ${SHELL:-ksh} -c 'print $#;[[ $1 != argument0 ]]' count $(longline $n) 2> /dev/null) 413*4887Schin do ((sum += $i)) 414*4887Schin done 415*4887Schin (( sum == n )) || err_exit "command -x processed only $sum arguments" 416*4887Schin command -p command -x ${SHELL:-ksh} -c 'print $#;[[ $1 == argument0 ]]' count $(longline $n) > /dev/null 2>&1 417*4887Schin [[ $? != 1 ]] && err_exit 'incorrect exit status for command -x' 418*4887Schinfi 419*4887Schin# test command -x option with extra arguments 420*4887Schininteger sum=0 n=10000 421*4887Schinif ! ${SHELL:-ksh} -c 'print $#' count $(longline $n) > /dev/null 2>&1 422*4887Schinthen for i in $(command command -x ${SHELL:-ksh} -c 'print $#;[[ $1 != argument0 ]]' count $(longline $n) one two three) #2> /dev/null) 423*4887Schin do ((sum += $i)) 424*4887Schin done 425*4887Schin (( sum > n )) || err_exit "command -x processed only $sum arguments" 426*4887Schin (( (sum-n)%3==0 )) || err_exit "command -x processed only $sum arguments" 427*4887Schin (( sum == n+3)) && err_exit "command -x processed only $sum arguments" 428*4887Schin command -p command -x ${SHELL:-ksh} -c 'print $#;[[ $1 == argument0 ]]' count $(longline $n) > /dev/null 2>&1 429*4887Schin [[ $? != 1 ]] && err_exit 'incorrect exit status for command -x' 430*4887Schinfi 431*4887Schin# test for debug trap 432*4887Schin[[ $(typeset -i i=0 433*4887Schin trap 'print $i' DEBUG 434*4887Schin while (( i <2)) 435*4887Schin do (( i++)) 436*4887Schin done) == $'0\n0\n1\n1\n2' ]] || err_exit "DEBUG trap not working" 437*4887Schingetconf UNIVERSE - ucb 438*4887Schin[[ $($SHELL -c 'echo -3') == -3 ]] || err_exit "echo -3 not working in ucb universe" 439*4887Schintypeset -F3 start_x=SECONDS total_t delay=0.02 440*4887Schintypeset reps=50 leeway=5 441*4887Schinsleep $(( 2 * leeway * reps * delay )) | 442*4887Schinfor (( i=0 ; i < reps ; i++ )) 443*4887Schindo read -N1 -t $delay 444*4887Schindone 445*4887Schin(( total_t = SECONDS - start_x )) 446*4887Schinif (( total_t > leeway * reps * delay )) 447*4887Schinthen err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long" 448*4887Schinelif (( total_t < reps * delay )) 449*4887Schinthen err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" 450*4887Schinfi 451*4887Schinexit $((Errors)) 452