KSH93 Compound Variables

Most shells, including bash, ksh88 and pdksh, implement a flat variable namespace.  According to Dave Korn, one of the lessons learned from UNIX is that a hierarchical namespace is better than a flat namespace.  For this reason, amongst others, a hierarchical variable namespace was implemented by him in ksh93, with . (dot) as the separator for each level of the hierarchy.  This expanded variable namespace enabled the implementation of an aggregate definition for a shell variable to include subvariables.  Such shell variables are called compound variables.  Not much appears to have been written about compound variables to date and, as usual, the ksh93 man page is terse on the subject.  This post will try to explain compound variables in detail and demonstrate how useful they can be in when dealing with structured data.

As in bash, ksh88, and pdksh, a variable in ksh93 is defined by a name=value pair.
$ myvar=10
$ print $myvar
10
Now consider the following commands which show how to declare a compound variable, define subvariables and interact with those subvariables.
$ typeset -C myvar       # declare 'myvar' as compound variable 
$ myvar.x=10 # set subvariable 'x' to 10
$ myvar.y=20 # set subvariable 'y' to 20
$ print $myvar # print definition of compound variable
( x=10 y=20 )
$ print ${myvar.x} # print value of 'x' subvariable
10
$ print ${myvar.y} # print value of 'y' subvariable
20
$ yourvar=( x=10 y=5 ) # declare and define 'yourvar' compound variable
$ print $yourvar
( x=10 y=5 )
$ print $(( yourvar.x * yourvar.y )) # multiply 2 subvariables together.
50
$
A variable with a . (dot,period) in it’s name is called a subvariable.  However to create a subvariable, a variable whose name consists of everything up to the period must already exist.  Note that variable names that begin with .sh are reserved for use by ksh93.

Just as var='' initializes a simple variable, var=() does the same for a compound variable. This is not assigning a value to var; it is simply declaring that var is a compound variable and its value will be defined by all subvariables of the form var.*.

You can specify the type of specific subvariables.  For example, to create a compound variable with a subvariable named x of type integer.
$ var=( typeset -i x=2 )
You can have more than one level of subvariables in a compound variable.  However, you must be careful to first declare the compound variable otherwise you will get an error.
$ var=
$ var.x.y=2
/bin/ksh93t: var.x.y=2: no parent
$ var=()
$ var.x.y=2
$ print $var
( x=( y=2 ) )
$
You can use += word with compound variables provided the types are compatable.  When += word is applied to an arithmetic type, word is added to the current value.  When applied to a string variable, word is appended to the value.
$ var=( str="abc" typeset -i num=12 )
$ var.str+="def"
$ var.num+=12
$ print ${var.}
( typeset -i num=24 str=abcdef )
$
You may be wondering why the value of a compound variable is outputted in the form that it is.  The reason is that value of a compound variable is intended to be in a form ready for reinput by ksh93 as shown by the following example.
$ var=( x=2 y=4 )
$ print $var
( x=2 y=4 )
$ print -r "newvar=$var" > file
$ unset var
$ print $var

$ . ./file
$ print $newvar
( x=2 y=4)
$
You can copy compound variables using the eval builtin.
$ var=( x=2 y=3 )
$ print $var
( x=2 y=3 )
$ eval "newvar=$var"
$ print $newvar
( x=2 y=3 )
$
You can create a new compound variable from part of a existing compound variable.
$ var=( x=1 y=2 )
$ var.y.a=1
$ var.y.b=2
$ var.y.c=3
$ print $var
( x=1 y=2 y=( a=1 b=2 c=3 .=2 ) )
$ eval "newvar=${var.y.}"
$ print $newvar
( a=1 b=2 c=3 .=2 )
$ print -r -- "newvar=${newvar.}"
newvar=(
a=1
b=2
c=3
.=2
)
$
Compound variables can be exported but subvariables cannot.
$ testvar=( x=12 )
$ echo ${testvar.x}
12
$ export testvar.x
/bin/ksh93: export: testvar.x: invalid export name
$ export testvar
$ env | grep testvar
testvar=(x=12;)
$
One thing you need to be aware of is that ksh93 also uses the . (dot) notation to denote what are called discipline functions.  Shell variables in ksh93 can also behave as active objects rather than as simple storage units by having a one or more functions associated with a variable.  These functions are called discipline functions.  A discipline function is defined like any other function, except that the name for a discipline function is formed by using the variable name, followed by a . (dot), followed by the discipline name.  Any variable can have discipline functions defined that are invoked when the variable is referenced or assigned a value.  The default set of discipline functions in ksh93 is get, set, and unset.  Other discipline functions can be defined via a custom shared library.

Compound variables are currently a work in progress.  Some of the examples that I have shown above may not work in future versions of ksh93.  These examples were tested on ksh93t 2008-07-24.

Well, that is about all you need to get you started using compound variables.  I hope this post has given you some ideas about how useful such variables could be in your future ksh93 scripts.

1 comments:

Anonymous said...

1. Copying via "eval" is obsolete - at least in ast-ksh.2008-11-04 you can simply do a a=b to copy the compound variable content from "b" to compound variable "a" (assuming both have been declared as compound variable)
2. Compound variables support the += operator to merge compound variables

Post a Comment