Introduction
Announcements

Schedule
Labs
Assignments
TA office hours

Tests, exam

Topic videos
Some course notes
Extra problems
Lecture recordings

Discussion board

Grades so far

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 ('{' and '}').

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 to create arrays indexed by integers, too.)

Suppose we want to do something equivalent to Python's:

	x['me'] = 'you'
That is to say, the associative array 'x' at index "me" has the value "you".

We will accomplish this by making a compound variable name; the above assignment statement then will look like this:

	xme=you

But that's 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 since that line doesn't begin with a word and an equals sign (there's the '$y' there), it's not an assignment statement.
Try it, and think about this point and make sure you understand why the above doesn't work, before we go further.

On the other hand, 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
The variable interpolation is performed, and then the line is re-parsed and executed -- that's what "eval" does.

Now, how do we access this associative array value?

Again, the easy case is if we want to do something like

	print x['me']
which we can do simply by
	echo $xme

The trickier case is to do 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" (because there's 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

To make sure you understand this, write a shell script which works like this:

	$ sh myscript hello goodbye
	Assigning "goodbye" to a["hello"]
	Now a["hello"] is goodbye
	$ 
But don't just output the above; actually do the variable (array) assignment, so that that "goodbye" which is the last word output above is the value retrieved from the array.

You can assume that there are no spaces or other interesting characters in either of the arguments (it's quite difficult to make this work if there can be interesting characters in either the subscript or the value).

Only after you have this working, you might want to look at my solution.


WARNING ABOUT BACKQUOTES (or '$()'): Backquotes also subject shell commands to repeated parsing. This causes problems with the use of backslashes.
If you want to do something like this:

	echo I think you should say `eval cat \$filename$greeting` soon.
(which won't work)
instead use single quotes around the dollar sign whose interpretation you wish to delay:
	echo I think you should say `eval cat '$'filename$greeting` soon.