xref: /titanic_41/usr/src/lib/libshell/common/tests/variables.sh (revision fc0105de770cee6a3fd91de949b9927fba6e894b)
1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2008 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
31[[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION'
32unset ss
33[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset'
34[[ ${!ss} == ss ]] ||  err_exit '${!ss} should be ss when ss is unset'
35[[ ${#ss} == 0 ]] ||  err_exit '${#ss} should be 0 when ss is unset'
36# RANDOM
37if	(( RANDOM==RANDOM || $RANDOM==$RANDOM ))
38then	err_exit RANDOM variable not working
39fi
40# SECONDS
41sleep 3
42if	(( SECONDS < 2 ))
43then	err_exit SECONDS variable not working
44fi
45# _
46set abc def
47if	[[ $_ != def ]]
48then	err_exit _ variable not working
49fi
50# ERRNO
51#set abc def
52#rm -f foobar#
53#ERRNO=
54#2> /dev/null < foobar#
55#if	(( ERRNO == 0 ))
56#then	err_exit ERRNO variable not working
57#fi
58# PWD
59if	[[ !  $PWD -ef . ]]
60then	err_exit PWD variable not working
61fi
62# PPID
63if	[[ $($SHELL -c 'print $PPID')  != $$ ]]
64then	err_exit PPID variable not working
65fi
66# OLDPWD
67old=$PWD
68cd /
69if	[[ $OLDPWD != $old ]]
70then	err_exit OLDPWD variable not working
71fi
72cd $old || err_exit cd failed
73# REPLY
74read <<-!
75	foobar
76	!
77if	[[ $REPLY != foobar ]]
78then	err_exit REPLY variable not working
79fi
80integer save=$LINENO
81# LINENO
82LINENO=10
83#
84#  These lines intentionally left blank
85#
86if	(( LINENO != 13))
87then	err_exit LINENO variable not working
88fi
89LINENO=save+10
90IFS=:
91x=a::b::c
92if	[[ $x != a::b::c ]]
93then	err_exit "Word splitting on constants"
94fi
95set -- $x
96if	[[ $# != 5 ]]
97then	err_exit ":: doesn't separate null arguments "
98fi
99set x
100if	x$1=0 2> /dev/null
101then	err_exit "x\$1=value treated as an assignment"
102fi
103# check for attributes across subshells
104typeset -i x=3
105y=1/0
106if	( typeset x=y ) 2> /dev/null
107then	err_exit "attributes not passed to subshells"
108fi
109unset x
110function x.set
111{
112	nameref foo=${.sh.name}.save
113	foo=${.sh.value}
114	.sh.value=$0
115}
116x=bar
117if	[[ $x != x.set ]]
118then	err_exit 'x.set does not override assignment'
119fi
120x.get()
121{
122	nameref foo=${.sh.name}.save
123	.sh.value=$foo
124}
125
126if	[[ $x != bar ]]
127then	err_exit 'x.get does not work correctly'
128fi
129typeset +n foo
130unset foo
131foo=bar
132(
133	unset foo
134	set +u
135	if	[[ $foo != '' ]]
136	then	err_exit '$foo not null after unset in subsehll'
137	fi
138)
139if	[[ $foo != bar ]]
140then	err_exit 'unset foo in subshell produces side effect '
141fi
142unset foo
143if	[[ $( { : ${foo?hi there} ; } 2>&1) != *'hi there' ]]
144then	err_exit '${foo?hi there} with foo unset does not print hi there on 2'
145fi
146x=$0
147set foobar
148if	[[ ${@:0} != "$x foobar" ]]
149then	err_exit '${@:0} not expanding correctly'
150fi
151set --
152if	[[ ${*:0:1} != "$0" ]]
153then	err_exit '${@:0} not expanding correctly'
154fi
155ACCESS=0
156function COUNT.set
157{
158        (( ACCESS++ ))
159}
160COUNT=0
161(( COUNT++ ))
162if	(( COUNT != 1 || ACCESS!=2 ))
163then	err_exit " set discipline failure COUNT=$COUNT ACCESS=$ACCESS"
164fi
165LANG=C > /dev/null 2>&1
166if	[[ $LANG != C ]]
167then	err_exit "C locale not working"
168fi
169unset RANDOM
170unset -n foo
171foo=junk
172function foo.get
173{
174	.sh.value=stuff
175	unset -f foo.get
176}
177if	[[ $foo != stuff ]]
178then	err_exit "foo.get discipline not working"
179fi
180if	[[ $foo != junk ]]
181then	err_exit "foo.get discipline not working after unset"
182fi
183# special variables
184set -- 1 2 3 4 5 6 7 8 9 10
185sleep 1000 &
186if	[[ $(print -r -- ${#10}) != 2 ]]
187then	err_exit '${#10}, where ${10}=10 not working'
188fi
189for i in @ '*' ! '#' - '?' '$'
190do	false
191	eval foo='$'$i bar='$'{$i}
192	if	[[ ${foo} != "${bar}" ]]
193	then	err_exit "\$$i not equal to \${$i}"
194	fi
195	command eval bar='$'{$i%?} 2> /dev/null || err_exit "\${$i%?} gives syntax error"
196	if	[[ $i != [@*] && ${foo%?} != "$bar"  ]]
197	then	err_exit "\${$i%?} not correct"
198	fi
199	command eval bar='$'{$i#?} 2> /dev/null || err_exit "\${$i#?} gives syntax error"
200	if	[[ $i != [@*] && ${foo#?} != "$bar"  ]]
201	then	err_exit "\${$i#?} not correct"
202	fi
203	command eval foo='$'{$i} bar='$'{#$i} || err_exit "\${#$i} gives synta
204x error"
205	if	[[ $i != @([@*]) && ${#foo} != "$bar" ]]
206	then	err_exit "\${#$i} not correct"
207	fi
208done
209kill $!
210unset x
211CDPATH=/
212x=$(cd tmp)
213if	[[ $x != /tmp ]]
214then	err_exit 'CDPATH does not display new directory'
215fi
216mkdir /tmp/ksh$$
217CDPATH=/:
218x=$(cd /tmp;cd ksh$$)
219if	[[ $x ]]
220then	err_exit 'CDPATH displays new directory when not used'
221fi
222x=$(cd tmp/ksh$$)
223if	[[ $x != /tmp/ksh$$ ]]
224then	err_exit "CDPATH tmp/ksh$$ does not display new directory"
225fi
226cd /
227rm -rf /tmp/ksh$$
228TMOUT=100
229(TMOUT=20)
230if	(( TMOUT !=100 ))
231then	err_exit 'setting TMOUT in subshell affects parent'
232fi
233unset y
234function setdisc # var
235{
236        eval function $1.get'
237        {
238                .sh.value=good
239        }
240        '
241}
242y=bad
243setdisc y
244if	[[ $y != good ]]
245then	err_exit 'setdisc function not working'
246fi
247integer x=$LINENO
248: $'\
249'
250if	(( LINENO != x+3  ))
251then	err_exit '\<newline> gets linenumber count wrong'
252fi
253set --
254set -- "${@-}"
255if	(( $# !=1 ))
256then	err_exit	'"${@-}" not expanding to null string'
257fi
258for i in : % + / 3b '**' '***' '@@' '{' '[' '}' !!  '*a' '$foo'
259do      (eval : \${"$i"} 2> /dev/null) && err_exit "\${$i} not an syntax error"
260done
261unset IFS
262( IFS='  ' ; read -r a b c <<-!
263	x  y z
264	!
265	if	[[ $b ]]
266	then	err_exit 'IFS="  " not causing adjacent space to be null string'
267	fi
268)
269read -r a b c <<-!
270x  y z
271!
272if	[[ $b != y ]]
273then	err_exit 'IFS not restored after subshell'
274fi
275
276# The next part generates 3428 IFS set/read tests.
277
278unset IFS x
279function split
280{
281	i=$1 s=$2 r=$3
282	IFS=': '
283	set -- $i
284	IFS=' '
285	g="[$#]"
286	while	:
287	do	case $# in
288		0)	break ;;
289		esac
290		g="$g($1)"
291		shift
292	done
293	case "$g" in
294	"$s")	;;
295	*)	err_exit "IFS=': '; set -- '$i'; expected '$s' got '$g'" ;;
296	esac
297	print "$i" | IFS=": " read arg rem; g="($arg)($rem)"
298	case "$g" in
299	"$r")	;;
300	*)	err_exit "IFS=': '; read '$i'; expected '$r' got '$g'" ;;
301	esac
302}
303for str in 	\
304	'-'	\
305	'a'	\
306	'- -'	\
307	'- a'	\
308	'a -'	\
309	'a b'	\
310	'- - -'	\
311	'- - a'	\
312	'- a -'	\
313	'- a b'	\
314	'a - -'	\
315	'a - b'	\
316	'a b -'	\
317	'a b c'
318do
319	IFS=' '
320	set x $str
321	shift
322	case $# in
323	0)	continue ;;
324	esac
325	f1=$1
326	case $f1 in
327	'-')	f1='' ;;
328	esac
329	shift
330	case $# in
331	0)	for d0 in '' ' '
332		do
333			for d1 in '' ' ' ':' ' :' ': ' ' : '
334			do
335				case $f1$d1 in
336				'')	split "$d0$f1$d1" "[0]" "()()" ;;
337				' ')	;;
338				*)	split "$d0$f1$d1" "[1]($f1)" "($f1)()" ;;
339				esac
340			done
341		done
342		continue
343		;;
344	esac
345	f2=$1
346	case $f2 in
347	'-')	f2='' ;;
348	esac
349	shift
350	case $# in
351	0)	for d0 in '' ' '
352		do
353			for d1 in ' ' ':' ' :' ': ' ' : '
354			do
355				case ' ' in
356				$f1$d1|$d1$f2)	continue ;;
357				esac
358				for d2 in '' ' ' ':' ' :' ': ' ' : '
359				do
360					case $f2$d2 in
361					'')	split "$d0$f1$d1$f2$d2" "[1]($f1)" "($f1)()" ;;
362					' ')	;;
363					*)	split "$d0$f1$d1$f2$d2" "[2]($f1)($f2)" "($f1)($f2)" ;;
364					esac
365				done
366			done
367		done
368		continue
369		;;
370	esac
371	f3=$1
372	case $f3 in
373	'-')	f3='' ;;
374	esac
375	shift
376	case $# in
377	0)	for d0 in '' ' '
378		do
379			for d1 in ':' ' :' ': ' ' : '
380			do
381				case ' ' in
382				$f1$d1|$d1$f2)	continue ;;
383				esac
384				for d2 in ' ' ':' ' :' ': ' ' : '
385				do
386					case $f2$d2 in
387					' ')	continue ;;
388					esac
389					case ' ' in
390					$f2$d2|$d2$f3)	continue ;;
391					esac
392					for d3 in '' ' ' ':' ' :' ': ' ' : '
393					do
394						case $f3$d3 in
395						'')	split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;;
396						' ')	;;
397						*)	x=$f2$d2$f3$d3
398							x=${x#' '}
399							x=${x%' '}
400							split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)"
401							;;
402						esac
403					done
404				done
405			done
406		done
407		continue
408		;;
409	esac
410done
411unset IFS
412
413if	[[ $( (print ${12345:?}) 2>&1) != *12345* ]]
414then	err_exit 'Incorrect error message with ${12345?}'
415fi
416unset foobar
417if	[[ $( (print ${foobar:?}) 2>&1) != *foobar* ]]
418then	err_exit 'Incorrect error message with ${foobar?}'
419fi
420unset bar
421if	[[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]]
422then	err_exit 'Incorrect error message with ${foobar?}'
423fi
424{ $SHELL -c '
425function foo
426{
427	typeset SECONDS=0
428	sleep 1.5
429	print $SECONDS
430
431}
432x=$(foo)
433(( x >1 && x < 2 ))
434'
435} 2> /dev/null   || err_exit 'SECONDS not working in function'
436trap 'rm -f /tmp/script$$ /tmp/out$$' EXIT
437cat > /tmp/script$$ <<-\!
438	posixfun()
439	{
440		unset x
441	 	nameref x=$1
442	 	print  -r -- "$x"
443	}
444	function fun
445	{
446	 	nameref x=$1
447	 	print  -r -- "$x"
448	}
449	if	[[ $1 ]]
450	then	file=${.sh.file}
451	else	print -r -- "${.sh.file}"
452	fi
453!
454chmod +x /tmp/script$$
455. /tmp/script$$  1
456[[ $file == /tmp/script$$ ]] || err_exit ".sh.file not working for dot scripts"
457[[ $($SHELL /tmp/script$$) == /tmp/script$$ ]] || err_exit ".sh.file not working for scripts"
458[[ $(posixfun .sh.file) == /tmp/script$$ ]] || err_exit ".sh.file not working for posix functions"
459[[ $(fun .sh.file) == /tmp/script$$ ]] || err_exit ".sh.file not working for functions"
460[[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions"
461[[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions"
462[[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions"
463[[ $(fun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for functions"
464(
465    [[ $(posixfun .sh.subshell) == 2 ]]  || err_exit ".sh.subshell not working for posix functions in subshells"
466    [[ $(fun .sh.subshell) == 2 ]]  || err_exit ".sh.subshell not working for functions in subshells"
467    (( .sh.subshell == 1 )) || err_exit ".sh.subshell not working in a subshell"
468)
469TIMEFORMAT='this is a test'
470[[ $({ { time :;} 2>&1;}) == "$TIMEFORMAT" ]] || err_exit 'TIMEFORMAT not working'
471: ${.sh.version}
472[[ $(alias integer) == *.sh.* ]] && err_exit '.sh. prefixed to alias name'
473: ${.sh.version}
474[[ $(whence rm) == *.sh.* ]] && err_exit '.sh. prefixed to tracked alias name'
475: ${.sh.version}
476[[ $(cd /bin;env | grep PWD=) == *.sh.* ]] && err_exit '.sh. prefixed to PWD'
477# unset discipline bug fix
478dave=dave
479function dave.unset
480{
481    unset dave
482}
483unset dave
484[[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed'
485
486print 'print ${VAR}' > /tmp/script$$
487unset VAR
488VAR=new /tmp/script$$ > /tmp/out$$
489got=$(</tmp/out$$)
490[[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'"
491[[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'"
492unset VAR
493VAR=old
494VAR=new /tmp/script$$ > /tmp/out$$
495got=$(</tmp/out$$)
496[[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'"
497[[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'"
498unset VAR
499export VAR=old
500VAR=new /tmp/script$$ > /tmp/out$$
501got=$(</tmp/out$$)
502[[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'"
503[[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'"
504
505(
506	unset dave
507	function  dave.append
508	{
509		.sh.value+=$dave
510		dave=
511	}
512	dave=foo; dave+=bar
513	[[ $dave == barfoo ]] || exit 2
514) 2> /dev/null
515case $? in
5160)	 ;;
5171)	 err_exit 'append discipline not implemented';;
518*)	 err_exit 'append discipline not working';;
519esac
520.sh.foobar=hello
521{
522	function .sh.foobar.get
523	{
524		.sh.value=world
525	}
526} 2> /dev/null || err_exit "Can't add get discipline to .sh.foobar"
527[[ ${.sh.foobar} == world ]]  || err_exit 'get discipline for .sh.foobar not working'
528x='a|b'
529IFS='|'
530set -- $x
531[[ $2 == b ]] || err_exit '$2 should be b after set'
532exec 3>&2 2> /dev/null
533set -x
534( IFS= ) 2> /dev/null
535set +x
536exec 2>&3-
537set -- $x
538[[ $2 == b ]] || err_exit '$2 should be b after subshell'
539: & pid=$!
540( : & )
541[[ $pid == $! ]] || err_exit '$! value not preserved across subshells'
542unset foo
543typeset -A foo
544function foo.set
545{
546	case ${.sh.subscript} in
547	bar)	if	((.sh.value > 1 ))
548	        then	.sh.value=5
549			foo[barrier_hit]=yes
550		fi
551		;;
552	barrier_hit)
553		if	[[ ${.sh.value} = yes ]]
554		then	foo[barrier_not_hit]=no
555		else	foo[barrier_not_hit]=yes
556		fi
557		;;
558	esac
559}
560foo[barrier_hit]=no
561foo[bar]=1
562(( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1'
563[[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no'
564[[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes'
565foo[barrier_hit]=no
566foo[bar]=2
567(( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5'
568[[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes'
569[[ ${foo[barrier_not_hit]} == no ]] || err_exit 'foo[barrier_not_hit] should be no'
570unset x
571typeset -i x
572function x.set
573{
574	typeset sub=${.sh.subscript}
575	(( sub > 0 )) && (( x[sub-1]= x[sub-1] + .sh.value ))
576}
577x[0]=0 x[1]=1 x[2]=2 x[3]=3
578[[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly'
579((SECONDS=3*4))
580(( SECONDS < 12 || SECONDS > 12.1 )) &&  err_exit "SECONDS is $SECONDS and should be close to 12"
581unset a
582function a.set
583{
584	print -r -- "${.sh.name}=${.sh.value}"
585}
586[[ $(a=1) == a=1 ]] || err_exit 'set discipline not working in subshell assignment'
587[[ $(a=1 :) == a=1 ]] || err_exit 'set discipline not working in subshell command'
588
589[[ ${.sh.subshell} == 0 ]] || err_exit '${.sh.subshell} should be 0'
590(
591	[[ ${.sh.subshell} == 1 ]] || err_exit '${.sh.subshell} should be 1'
592	(
593		[[ ${.sh.subshell} == 2 ]] || err_exit '${.sh.subshell} should be 2'
594	)
595)
596
597set -- {1..32768}
598(( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#"
599set --
600
601unset r v x
602path=$PATH
603x=foo
604for v in EDITOR VISUAL OPTIND CDPATH FPATH PATH ENV LINENO RANDOM SECONDS _
605do	nameref r=$v
606	unset $v
607	if	( $SHELL -c "unset $v; : \$$v" ) 2>/dev/null
608	then	[[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'"
609		r=$x
610		[[ $r == $x ]] || err_exit "$v=$x failed -- expected '$x', got '$r'"
611	else	err_exit "unset $v; : \$$v failed"
612	fi
613done
614for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC
615do	nameref r=$v
616	unset $v
617	[[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'"
618	d=$($SHELL -c "$v=$x" 2>&1)
619	[[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic"
620	( r=$x; [[ ! $r ]] ) 2>/dev/null || err_exit "$v=$x failed -- expected ''"
621	( r=C; r=$x; [[ $r == C ]] ) 2>/dev/null || err_exit "$v=C; $v=$x failed -- expected 'C'"
622done
623PATH=$path
624
625exit $((Errors))
626