1da2e3ebdSchin######################################################################## 2da2e3ebdSchin# # 3da2e3ebdSchin# This software is part of the ast package # 4*3e14f97fSRoger A. Faulkner# Copyright (c) 1982-2010 AT&T Intellectual Property # 5da2e3ebdSchin# and is licensed under the # 6da2e3ebdSchin# Common Public License, Version 1.0 # 77c2fbfb3SApril Chin# by AT&T Intellectual Property # 8da2e3ebdSchin# # 9da2e3ebdSchin# A copy of the License is available at # 10da2e3ebdSchin# http://www.opensource.org/licenses/cpl1.0.txt # 11da2e3ebdSchin# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # 12da2e3ebdSchin# # 13da2e3ebdSchin# Information and Software Systems Research # 14da2e3ebdSchin# AT&T Research # 15da2e3ebdSchin# Florham Park NJ # 16da2e3ebdSchin# # 17da2e3ebdSchin# David Korn <dgk@research.att.com> # 18da2e3ebdSchin# # 19da2e3ebdSchin######################################################################## 20da2e3ebdSchinfunction err_exit 21da2e3ebdSchin{ 22da2e3ebdSchin print -u2 -n "\t" 23da2e3ebdSchin print -u2 -r ${Command}[$1]: "${@:2}" 24da2e3ebdSchin let Errors+=1 25da2e3ebdSchin} 26da2e3ebdSchinalias err_exit='err_exit $LINENO' 27da2e3ebdSchin 28da2e3ebdSchinCommand=${0##*/} 29da2e3ebdSchininteger Errors=0 3034f9b3eeSRoland Mainz 3134f9b3eeSRoland Mainztmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } 3234f9b3eeSRoland Mainztrap "cd /; rm -rf $tmp" EXIT 3334f9b3eeSRoland Mainz 3434f9b3eeSRoland Mainz# test basic file operations like redirection, pipes, file expansion 357c2fbfb3SApril Chinset -- \ 367c2fbfb3SApril Chin go+r 0000 \ 377c2fbfb3SApril Chin go-r 0044 \ 387c2fbfb3SApril Chin ug=r 0330 \ 397c2fbfb3SApril Chin go+w 0000 \ 407c2fbfb3SApril Chin go-w 0022 \ 417c2fbfb3SApril Chin ug=w 0550 \ 427c2fbfb3SApril Chin go+x 0000 \ 437c2fbfb3SApril Chin go-x 0011 \ 447c2fbfb3SApril Chin ug=x 0660 \ 457c2fbfb3SApril Chin go-rx 0055 \ 467c2fbfb3SApril Chin uo-wx 0303 \ 477c2fbfb3SApril Chin ug-rw 0660 \ 487c2fbfb3SApril Chin o= 0007 497c2fbfb3SApril Chinwhile (( $# >= 2 )) 507c2fbfb3SApril Chindo umask 0 517c2fbfb3SApril Chin umask $1 527c2fbfb3SApril Chin g=$(umask) 537c2fbfb3SApril Chin [[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g" 547c2fbfb3SApril Chin shift 2 557c2fbfb3SApril Chindone 56da2e3ebdSchinumask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" 57da2e3ebdSchinif [[ $(umask -S) != u=rwx,g=rx,o=rx ]] 58da2e3ebdSchinthen err_exit 'umask -S incorrect' 59da2e3ebdSchinfi 60da2e3ebdSchinpwd=$PWD 61da2e3ebdSchin[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL 6234f9b3eeSRoland Mainzcd $tmp || { err_exit "cd $tmp failed"; exit 1; } 637c2fbfb3SApril Chinum=$(umask -S) 647c2fbfb3SApril Chin( umask 0777; > foobar ) 657c2fbfb3SApril Chinrm -f foobar 667c2fbfb3SApril Chin> foobar 677c2fbfb3SApril Chin[[ -r foobar ]] || err_exit 'umask not being restored after subshell' 687c2fbfb3SApril Chinumask "$um" 697c2fbfb3SApril Chinrm -f foobar 70da2e3ebdSchin# optimizer bug test 71da2e3ebdSchin> foobar 72da2e3ebdSchinfor i in 1 2 73da2e3ebdSchindo print foobar* 74da2e3ebdSchin rm -f foobar 7534f9b3eeSRoland Mainzdone > out 7634f9b3eeSRoland Mainzif [[ "$(<out)" != "foobar"$'\n'"foobar*" ]] 77da2e3ebdSchinthen print -u2 "optimizer bug with file expansion" 78da2e3ebdSchinfi 7934f9b3eeSRoland Mainzrm -f out foobar 80da2e3ebdSchinmkdir dir 81da2e3ebdSchinif [[ $(print */) != dir/ ]] 82da2e3ebdSchinthen err_exit 'file expansion with trailing / not working' 83da2e3ebdSchinfi 84da2e3ebdSchinif [[ $(print *) != dir ]] 85da2e3ebdSchinthen err_exit 'file expansion with single file not working' 86da2e3ebdSchinfi 87da2e3ebdSchinprint hi > .foo 88da2e3ebdSchinif [[ $(print *) != dir ]] 89da2e3ebdSchinthen err_exit 'file expansion leading . not working' 90da2e3ebdSchinfi 91da2e3ebdSchindate > dat1 || err_exit "date > dat1 failed" 92da2e3ebdSchintest -r dat1 || err_exit "dat1 is not readable" 93da2e3ebdSchinx=dat1 94da2e3ebdSchincat <$x > dat2 || err_exit "cat < $x > dat2 failed" 95da2e3ebdSchincat dat1 dat2 | cat | cat | cat > dat3 || err_exit "cat pipe failed" 96da2e3ebdSchincat > dat4 <<! 97da2e3ebdSchin$(date) 98da2e3ebdSchin! 99da2e3ebdSchincat dat1 dat2 | cat | cat | cat > dat5 & 100da2e3ebdSchinwait $! 101da2e3ebdSchinset -- dat* 102da2e3ebdSchinif (( $# != 5 )) 103da2e3ebdSchinthen err_exit "dat* matches only $# files" 104da2e3ebdSchinfi 105da2e3ebdSchinif (command > foo\\abc) 2> /dev/null 106da2e3ebdSchinthen set -- foo* 107da2e3ebdSchin if [[ $1 != 'foo\abc' ]] 108da2e3ebdSchin then err_exit 'foo* does not match foo\abc' 109da2e3ebdSchin fi 110da2e3ebdSchinfi 111da2e3ebdSchinif ( : > TT* && : > TTfoo ) 2>/dev/null 112da2e3ebdSchinthen set -- TT* 113da2e3ebdSchin if (( $# < 2 )) 114da2e3ebdSchin then err_exit 'TT* not expanding when file TT* exists' 115da2e3ebdSchin fi 116da2e3ebdSchinfi 117da2e3ebdSchincd ~- || err_exit "cd back failed" 11834f9b3eeSRoland Mainzcat > $tmp/script <<- ! 119da2e3ebdSchin #! $SHELL 120da2e3ebdSchin print -r -- \$0 121da2e3ebdSchin! 12234f9b3eeSRoland Mainzchmod 755 $tmp/script 12334f9b3eeSRoland Mainzif [[ $($tmp/script) != "$tmp/script" ]] 124da2e3ebdSchinthen err_exit '$0 not correct for #! script' 125da2e3ebdSchinfi 126da2e3ebdSchinbar=foo 127da2e3ebdSchineval foo=\$bar 128da2e3ebdSchinif [[ $foo != foo ]] 129da2e3ebdSchinthen err_exit 'eval foo=\$bar not working' 130da2e3ebdSchinfi 131da2e3ebdSchinbar='foo=foo\ bar' 132da2e3ebdSchineval $bar 133da2e3ebdSchinif [[ $foo != 'foo bar' ]] 134da2e3ebdSchinthen err_exit 'eval foo=\$bar, with bar="foo\ bar" not working' 135da2e3ebdSchinfi 136da2e3ebdSchincd /tmp 137da2e3ebdSchincd ../../tmp || err_exit "cd ../../tmp failed" 138da2e3ebdSchinif [[ $PWD != /tmp ]] 139da2e3ebdSchinthen err_exit 'cd ../../tmp is not /tmp' 140da2e3ebdSchinfi 141da2e3ebdSchin( sleep 2; cat <<! 142da2e3ebdSchinfoobar 143da2e3ebdSchin! 14434f9b3eeSRoland Mainz) | cat > $tmp/foobar & 145da2e3ebdSchinwait $! 14634f9b3eeSRoland Mainzfoobar=$( < $tmp/foobar) 147da2e3ebdSchinif [[ $foobar != foobar ]] 148da2e3ebdSchinthen err_exit "$foobar is not foobar" 149da2e3ebdSchinfi 150da2e3ebdSchin{ 151da2e3ebdSchin print foo 152da2e3ebdSchin /bin/echo bar 153da2e3ebdSchin print bam 15434f9b3eeSRoland Mainz} > $tmp/foobar 15534f9b3eeSRoland Mainzif [[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]] 15634f9b3eeSRoland Mainzthen err_exit "output file pointer not shared correctly" 157da2e3ebdSchinfi 15834f9b3eeSRoland Mainzcat > $tmp/foobar <<\! 159da2e3ebdSchin print foo 160da2e3ebdSchin /bin/echo bar 161da2e3ebdSchin print bam 162da2e3ebdSchin! 16334f9b3eeSRoland Mainzchmod +x $tmp/foobar 16434f9b3eeSRoland Mainzif [[ $($tmp/foobar) != $'foo\nbar\nbam' ]] 16534f9b3eeSRoland Mainzthen err_exit "script not working" 166da2e3ebdSchinfi 16734f9b3eeSRoland Mainzif [[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]] 16834f9b3eeSRoland Mainzthen err_exit "script | cat not working" 169da2e3ebdSchinfi 17034f9b3eeSRoland Mainzif [[ $( $tmp/foobar) != $'foo\nbar\nbam' ]] 17134f9b3eeSRoland Mainzthen err_exit "output file pointer not shared correctly" 172da2e3ebdSchinfi 17334f9b3eeSRoland Mainzrm -f $tmp/foobar 174da2e3ebdSchinx=$( (print foo) ; (print bar) ) 175da2e3ebdSchinif [[ $x != $'foo\nbar' ]] 176da2e3ebdSchinthen err_exit " ( (print foo);(print bar ) failed" 177da2e3ebdSchinfi 178da2e3ebdSchinx=$( (/bin/echo foo) ; (print bar) ) 179da2e3ebdSchinif [[ $x != $'foo\nbar' ]] 180da2e3ebdSchinthen err_exit " ( (/bin/echo);(print bar ) failed" 181da2e3ebdSchinfi 182da2e3ebdSchinx=$( (/bin/echo foo) ; (/bin/echo bar) ) 183da2e3ebdSchinif [[ $x != $'foo\nbar' ]] 184da2e3ebdSchinthen err_exit " ( (/bin/echo);(/bin/echo bar ) failed" 185da2e3ebdSchinfi 18634f9b3eeSRoland Mainzcat > $tmp/script <<\! 187da2e3ebdSchinif [[ -p /dev/fd/0 ]] 188da2e3ebdSchinthen builtin cat 189da2e3ebdSchin cat - > /dev/null 190da2e3ebdSchin [[ -p /dev/fd/0 ]] && print ok 191da2e3ebdSchinelse print no 192da2e3ebdSchinfi 193da2e3ebdSchin! 19434f9b3eeSRoland Mainzchmod +x $tmp/script 19534f9b3eeSRoland Mainzcase $( (print) | $tmp/script;:) in 196da2e3ebdSchinok) ;; 197da2e3ebdSchinno) err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;; 198da2e3ebdSchin*) err_exit "builtin replaces standard input pipe" ;; 199da2e3ebdSchinesac 20034f9b3eeSRoland Mainzprint 'print $0' > $tmp/script 20134f9b3eeSRoland Mainzprint ". $tmp/script" > $tmp/scriptx 20234f9b3eeSRoland Mainzchmod +x $tmp/scriptx 20334f9b3eeSRoland Mainzif [[ $($tmp/scriptx) != $tmp/scriptx ]] 204da2e3ebdSchinthen err_exit '$0 not correct for . script' 205da2e3ebdSchinfi 20634f9b3eeSRoland Mainzcd $tmp || { err_exit "cd $tmp failed"; exit 1; } 207da2e3ebdSchinprint ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e 208da2e3ebdSchinchmod 755 a b c d e 209da2e3ebdSchinx=$(./a) 210da2e3ebdSchinif [[ $x != "hello there" ]] 211da2e3ebdSchinthen err_exit "nested scripts failed" 212da2e3ebdSchinfi 213da2e3ebdSchinx=$( (./a) | cat) 214da2e3ebdSchinif [[ $x != "hello there" ]] 215da2e3ebdSchinthen err_exit "scripts in subshells fail" 216da2e3ebdSchinfi 217da2e3ebdSchincd ~- || err_exit "cd back failed" 218da2e3ebdSchinx=$( (/bin/echo foo) 2> /dev/null ) 219da2e3ebdSchinif [[ $x != foo ]] 220da2e3ebdSchinthen err_exit "subshell in command substitution fails" 221da2e3ebdSchinfi 222da2e3ebdSchinexec 1>&- 223da2e3ebdSchinx=$(print hello) 224da2e3ebdSchinif [[ $x != hello ]] 225da2e3ebdSchinthen err_exit "command subsitution with stdout closed failed" 226da2e3ebdSchinfi 227da2e3ebdSchincd $pwd 228da2e3ebdSchinx=$(cat <<\! | $SHELL 229da2e3ebdSchin/bin/echo | /bin/cat 230da2e3ebdSchin/bin/echo hello 231da2e3ebdSchin! 232da2e3ebdSchin) 233da2e3ebdSchinif [[ $x != $'\n'hello ]] 234da2e3ebdSchinthen err_exit "$SHELL not working when standard input is a pipe" 235da2e3ebdSchinfi 236da2e3ebdSchinx=$( (/bin/echo hello) 2> /dev/null ) 237da2e3ebdSchinif [[ $x != hello ]] 238da2e3ebdSchinthen err_exit "subshell in command substitution with 1 closed fails" 239da2e3ebdSchinfi 24034f9b3eeSRoland Mainzcat > $tmp/script <<- \! 241da2e3ebdSchinread line 2> /dev/null 242da2e3ebdSchinprint done 243da2e3ebdSchin! 24434f9b3eeSRoland Mainzif [[ $($SHELL $tmp/script <&-) != done ]] 245da2e3ebdSchinthen err_exit "executing script with 0 closed fails" 246da2e3ebdSchinfi 247da2e3ebdSchintrap '' INT 24834f9b3eeSRoland Mainzcat > $tmp/script <<- \! 249da2e3ebdSchintrap 'print bad' INT 250da2e3ebdSchinkill -s INT $$ 251da2e3ebdSchinprint good 252da2e3ebdSchin! 25334f9b3eeSRoland Mainzchmod +x $tmp/script 25434f9b3eeSRoland Mainzif [[ $($SHELL $tmp/script) != good ]] 255da2e3ebdSchinthen err_exit "traps ignored by parent not ignored" 256da2e3ebdSchinfi 257da2e3ebdSchintrap - INT 25834f9b3eeSRoland Mainzcat > $tmp/script <<- \! 259da2e3ebdSchinread line 260da2e3ebdSchin/bin/cat 261da2e3ebdSchin! 26234f9b3eeSRoland Mainzif [[ $($SHELL $tmp/script <<! 263da2e3ebdSchinone 264da2e3ebdSchintwo 265da2e3ebdSchin! 266da2e3ebdSchin) != two ]] 267da2e3ebdSchinthen err_exit "standard input not positioned correctly" 268da2e3ebdSchinfi 269da2e3ebdSchinword=$(print $'foo\nbar' | { read line; /bin/cat;}) 270da2e3ebdSchinif [[ $word != bar ]] 271da2e3ebdSchinthen err_exit "pipe to { read line; /bin/cat;} not working" 272da2e3ebdSchinfi 273da2e3ebdSchinword=$(print $'foo\nbar' | ( read line; /bin/cat) ) 274da2e3ebdSchinif [[ $word != bar ]] 275da2e3ebdSchinthen err_exit "pipe to ( read line; /bin/cat) not working" 276da2e3ebdSchinfi 277da2e3ebdSchinif [[ $(print x{a,b}y) != 'xay xby' ]] 278da2e3ebdSchinthen err_exit 'brace expansion not working' 279da2e3ebdSchinfi 280da2e3ebdSchinif [[ $(for i in foo bar 281da2e3ebdSchin do ( tgz=$(print $i) 282da2e3ebdSchin print $tgz) 283da2e3ebdSchin done) != $'foo\nbar' ]] 284da2e3ebdSchinthen err_exit 'for loop subshell optimizer bug' 285da2e3ebdSchinfi 286da2e3ebdSchinunset a1 287da2e3ebdSchinoptbug() 288da2e3ebdSchin{ 289da2e3ebdSchin set -A a1 foo bar bam 290da2e3ebdSchin integer i 291da2e3ebdSchin for ((i=0; i < 3; i++)) 292da2e3ebdSchin do 293da2e3ebdSchin (( ${#a1[@]} < 2 )) && return 0 294da2e3ebdSchin set -- "${a1[@]}" 295da2e3ebdSchin shift 296da2e3ebdSchin set -A a1 -- "$@" 297da2e3ebdSchin done 298da2e3ebdSchin return 1 299da2e3ebdSchin} 300da2e3ebdSchinoptbug || err_exit 'array size optimzation bug' 3017c2fbfb3SApril Chinwait # not running --pipefail which would interfere with subsequent tests 302da2e3ebdSchin: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect) 303da2e3ebdSchinsleep 20 & 3047c2fbfb3SApril Chinpids=$! 305da2e3ebdSchinif [[ $(jobs -p) != $! ]] 306da2e3ebdSchinthen err_exit 'jobs -p not reporting a background job' 307da2e3ebdSchinfi 308da2e3ebdSchinsleep 20 & 3097c2fbfb3SApril Chinpids="$pids $!" 310da2e3ebdSchinfoo() 311da2e3ebdSchin{ 312da2e3ebdSchin set -- $(jobs -p) 313da2e3ebdSchin (( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected" 314da2e3ebdSchin} 315da2e3ebdSchinfoo 3167c2fbfb3SApril Chinkill $pids 3177c2fbfb3SApril Chin 3187c2fbfb3SApril Chin[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working' 319da2e3ebdSchin[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored' 320da2e3ebdSchin[[ $($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' 321da2e3ebdSchincommand exec 3<> /dev/null 322da2e3ebdSchinif cat /dev/fd/3 >/dev/null 2>&1 323da2e3ebdSchinthen [[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working' 32434f9b3eeSRoland Mainz [[ $($SHELL -c $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! 325da2e3ebdSchin line0 326da2e3ebdSchin line1 327da2e3ebdSchin line2 328da2e3ebdSchin !!! 329da2e3ebdSchin wait 33034f9b3eeSRoland Mainz cat '$tmp/scriptx 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' 33134f9b3eeSRoland Mainz > $tmp/scriptx 332da2e3ebdSchin [[ $($SHELL -c $' 333da2e3ebdSchin for i in 1 33434f9b3eeSRoland Mainz do tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! 335da2e3ebdSchin line0 336da2e3ebdSchin line1 337da2e3ebdSchin line2 338da2e3ebdSchin !!! 339da2e3ebdSchin done 340da2e3ebdSchin wait 34134f9b3eeSRoland Mainz cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' 342da2e3ebdSchin [[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] || 343da2e3ebdSchin err_exit 'process substitution of compound commands not working' 344da2e3ebdSchinfi 345da2e3ebdSchin[[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]] || err_exit 'command -p not restricted' 34634f9b3eeSRoland Mainzprint cat > $tmp/scriptx 34734f9b3eeSRoland Mainzchmod +x $tmp/scriptx 34834f9b3eeSRoland Mainz[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' 349da2e3ebdSchin[[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure' 350da2e3ebdSchin[[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure' 3517c2fbfb3SApril Chinexec 3<&- 352da2e3ebdSchinif [[ -d /dev/fd && -w /dev/fd/3 ]] 353da2e3ebdSchinthen [[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not working outside for or while loop" 354da2e3ebdSchin $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" 355da2e3ebdSchinfi 356da2e3ebdSchinexec 3> /dev/null 35734f9b3eeSRoland Mainzprint 'print foo "$@"' > $tmp/scriptx 35834f9b3eeSRoland Mainz[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' 35934f9b3eeSRoland Mainzprint "#! $SHELL" > $tmp/scriptx 36034f9b3eeSRoland Mainzprint 'print -- $0' >> $tmp/scriptx 36134f9b3eeSRoland Mainzchmod +x $tmp/scriptx 36234f9b3eeSRoland Mainz[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit "\$0 is $0 instead of $tmp/scriptx" 36334f9b3eeSRoland Mainzcat > $tmp/scriptx <<- \EOF 3647c2fbfb3SApril Chin myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} 3657c2fbfb3SApril Chin set -o pipefail 3667c2fbfb3SApril Chin sleep 3 | myfilter 3677c2fbfb3SApril ChinEOF 36834f9b3eeSRoland Mainz(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' 369da2e3ebdSchinexec 3<&- 370da2e3ebdSchin( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' 3717c2fbfb3SApril Chin$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' 3727c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substitution not supported' 3737c2fbfb3SApril Chin x=${ 3747c2fbfb3SApril Chin print hello 3757c2fbfb3SApril Chin } 3767c2fbfb3SApril Chin [[ $x == hello ]] 3777c2fbfb3SApril ChinEOF 3787c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substitution with side effects not supported ' 3797c2fbfb3SApril Chin y=bye 3807c2fbfb3SApril Chin x=${ 3817c2fbfb3SApril Chin y=hello 3827c2fbfb3SApril Chin print hello 3837c2fbfb3SApril Chin } 3847c2fbfb3SApril Chin [[ $y == $x ]] 3857c2fbfb3SApril ChinEOF 3867c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit 'nested ${...} command substitution not supported' 3877c2fbfb3SApril Chin x=${ 3887c2fbfb3SApril Chin print ${ print hello;} $(print world) 3897c2fbfb3SApril Chin } 3907c2fbfb3SApril Chin [[ $x == 'hello world' ]] 3917c2fbfb3SApril ChinEOF 3927c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }' 3937c2fbfb3SApril Chin x=${ { print -n } ; print -n hello ; } ; print ' world' } 3947c2fbfb3SApril Chin [[ $x == '}hello world' ]] 3957c2fbfb3SApril ChinEOF 3967c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working' 3977c2fbfb3SApril Chin f() 3987c2fbfb3SApril Chin { 3997c2fbfb3SApril Chin print foo 4007c2fbfb3SApril Chin } 4017c2fbfb3SApril Chin [[ ${ f;}bar == foobar ]] 4027c2fbfb3SApril ChinEOF 4037c2fbfb3SApril Chin 4047c2fbfb3SApril Chinunset foo 4057c2fbfb3SApril Chin[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' 4067c2fbfb3SApril Chin[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' 4077c2fbfb3SApril Chin[[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' 4087c2fbfb3SApril Chin[[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' 4097c2fbfb3SApril Chinunset foo 4107c2fbfb3SApril Chinfoo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false' 4117c2fbfb3SApril Chinexpected=foreback 4127c2fbfb3SApril Chingot=$(print -n fore;(sleep 2;print back)&) 4137c2fbfb3SApril Chin[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'" 4147c2fbfb3SApril Chin 41534f9b3eeSRoland Mainzbinfalse=$(whence -p false) 41634f9b3eeSRoland Mainzfor false in false $binfalse 4177c2fbfb3SApril Chindo x=$($false) && err_exit "x=\$($false) should fail" 4187c2fbfb3SApril Chin $($false) && err_exit "\$($false) should fail" 4197c2fbfb3SApril Chin $($false) > /dev/null && err_exit "\$($false) > /dev/null should fail" 4207c2fbfb3SApril Chindone 42134f9b3eeSRoland Mainzif env x-a=y >/dev/null 2>&1 42234f9b3eeSRoland Mainzthen [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' 42334f9b3eeSRoland Mainzfi 42434f9b3eeSRoland Mainzfloat s=SECONDS 42534f9b3eeSRoland Mainzsleep=$(whence -p sleep) 42634f9b3eeSRoland Mainzfor i in 1 2 42734f9b3eeSRoland Mainzdo print $i 42834f9b3eeSRoland Mainzdone | while read sec; do ( $sleep $sec; $sleep $sec) done 42934f9b3eeSRoland Mainz(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast' 43034f9b3eeSRoland Mainzs=SECONDS 43134f9b3eeSRoland Mainzset -o pipefail 43234f9b3eeSRoland Mainzfor ((i=0; i < 30; i++)) 43334f9b3eeSRoland Mainzdo print hello 43434f9b3eeSRoland Mainz sleep .1 43534f9b3eeSRoland Mainzdone | $sleep 1 43634f9b3eeSRoland Mainz(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe' 43734f9b3eeSRoland Mainz[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered' 43834f9b3eeSRoland Mainzvar=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!) 43934f9b3eeSRoland Mainz[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered' 44034f9b3eeSRoland Mainz 44134f9b3eeSRoland Mainzexp= 44234f9b3eeSRoland Mainzgot=$( 44334f9b3eeSRoland Mainz function fun 44434f9b3eeSRoland Mainz { 44534f9b3eeSRoland Mainz $binfalse && echo FAILED 44634f9b3eeSRoland Mainz } 44734f9b3eeSRoland Mainz : works if this line deleted : | 44834f9b3eeSRoland Mainz fun 44934f9b3eeSRoland Mainz : works if this line deleted : 45034f9b3eeSRoland Mainz) 45134f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'" 45234f9b3eeSRoland Mainzgot=$( 45334f9b3eeSRoland Mainz : works if this line deleted : | 45434f9b3eeSRoland Mainz { $binfalse && echo FAILED; } 45534f9b3eeSRoland Mainz : works if this line deleted : 45634f9b3eeSRoland Mainz) 45734f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'" 45834f9b3eeSRoland Mainz 45934f9b3eeSRoland Mainzgot=$( 46034f9b3eeSRoland Mainz : works if this line deleted : | 46134f9b3eeSRoland Mainz ( $binfalse && echo FAILED ) 46234f9b3eeSRoland Mainz : works if this line deleted : 46334f9b3eeSRoland Mainz) 46434f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'" 46534f9b3eeSRoland Mainz 46634f9b3eeSRoland Mainz( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null || err_exit 'trap DEBUG fails' 46734f9b3eeSRoland Mainz 468*3e14f97fSRoger A. Faulknertrue=$(whence -p true) 469*3e14f97fSRoger A. Faulknerset -o pipefail 470*3e14f97fSRoger A. Faulknerfloat start=$SECONDS end 471*3e14f97fSRoger A. Faulknerfor ((i=0; i < 2; i++)) 472*3e14f97fSRoger A. Faulknerdo print foo 473*3e14f97fSRoger A. Faulkner sleep 1.5 474*3e14f97fSRoger A. Faulknerdone | { read; $true; end=$SECONDS ;} 475*3e14f97fSRoger A. Faulkner(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish" 476*3e14f97fSRoger A. Faulknerset +o pipefail 477*3e14f97fSRoger A. Faulkner(( (SECONDS-start) > 2 )) && err_exit "pipefail causing /bin/true to wait for other end of pipe" 478*3e14f97fSRoger A. Faulkner 479*3e14f97fSRoger A. Faulkner 480*3e14f97fSRoger A. Faulkner{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails" 481*3e14f97fSRoger A. Faulkner 482da2e3ebdSchinexit $((Errors)) 483