Associative arrays in sh

An array is normally indexed by integers from 0 to n-1. An "associative array" is instead indexed by an arbitrary string, so it is a general mapping of strings to strings.

In Python, associative arrays are called "dictionaries" and are constructed with brace brackets ({}). (this is worth mentioning because some (all?) of them will know this in Python)

Sh doesn't have associative arrays, indeed it doesn't have arrays at all, but we can produce something basically equivalent to associative arrays with a little trickery. (So this can be used in place of traditional arrays, too.)

Suppose we want to do something equivalent to:

        x['me'] = 'you'
We could make a compound variable name "xme" and thus assign:
        xme=you
But this is the easy case. Suppose instead we want to do something like
        x[y] = 'you'
The following won't quite work:
        x$y=you
It's pretty close, but the assignments are interpreted before variable interpolation.

Whereas, the output from this looks quite fine:

        echo x$y=you
It outputs ("xme=you"). So how then do we execute that as a statement?

The sh command "eval" reinterprets a line before executing it. This is going to get trickier shortly, but here we just need

        eval x$y=you
Now, how do we access this associative array value?

Again, the easy case is something like

        print x['me']
which we can do simply by
        echo $xme
The trickier case is something like
        print x[y]
for which we can't do
        echo $x$y
because that just accesses the variables x and y separately.

How do we use eval here? The following is also wrong:

        eval echo $x$y
because it expands $x to whatever is in variable x (maybe nothing), and expands $y to "me", so we just have "eval echo me" which is no different from "echo me" (nothing additional to interpret by interpretating the command-line again before executing).

The key is to realize that we want the two dollar-signs above to be interpreted at different times! We want $y to be expanded to "me" first, then it would be "echo $xme", then we want $xme to be expanded.

What is the output from

        echo \$x$y
? (answer: "$xme")

So this is what we want interpreted. So the answer is

        eval echo \$x$y
Of course we don't have to use the command "echo" here. It can be whatever we want to do with the value. For example, if we wanted to cat the file x[y], we would write
        eval cat \$x$y

But even if you eventually want to write this 'cat' statement, you might find the 'echo' version helpful for developing and debugging trickier constructs of this nature.


A TA contributed the idea for an example program: When you run it, first type names of fruit and their colours (or really, any pairs of strings); then give your end-of-file signal (by default, it's control-D at the beginning of a line), then type queries and it will give you the colours for each fruit.

Example session:

    % sh fruitcolour 
    apple red
    banana yellow
(here I pressed control-D)
    What fruit do you want to know the colour of?
    banana
    banana is yellow
Solution in /u/ajr/209/tut/02/fruitcolour on CDF, or here: fruitcolour


[26 Sept tutorial exercises]
[list of tutorial notes web pages]