views:

259

answers:

3

In Bash I can create a map (hashtable) with this common construction

hput() {
  eval "$1""$2"='$3'
}

hget() {
  eval echo '${'"$1$2"'#hash}'
}

and then use it like this:

hput capitals France Paris
hput capitals Spain Madrid
echo "$(hget capitols France)"

But how do I best iterate over the entries in the map ?. For instance, in Java I would do:

for (Map.Entry<String, String> entry : capitals.entrySet()) {
  System.out.println("Country " + entry.getKey() + " capital " + entry.getValue());
}

is there a common way of accomplishing something similar in Bash ?.

+1  A: 
hkeys() {
    set | grep -o "^${1}[[:alnum:]]*=" | sed -re "s/^${1}(.*)=/\\1/g"
}
for key in $(hkeys capitols) ; do
    echo $key
done

And your hget function is wrong. Try this:

hput capitols Smth hash
hget capitols Smth

Second command should return the string hash, but it returned nothing. Remove «#hash» string from your function.

Also, echo "$(hget capitols France)" is ambigious. You can use hget capitols France instead.

ZyX
+3  A: 

if you have bash 4.0 , you can use associative arrays. else you can make use of awks associative arrays

ghostdog74
I am on Bash 3 so the awk solution looks far better than rolling my own. Thanks.
Lars Tackmann
+3  A: 

Here's one way to do it:

for h in ${!capitols*}; do indirect=$capitols$h; echo ${!indirect}; done

Here's another:

for h in ${!capitols*}; do key=${h#capitols*}; hget capitols $key; done

And another:

hiter() { 
    for h in $(eval echo '${!'$1'*}')
    do
        key=${h#$1*}
        echo -n "$key "
        hget $1 $key
    done
}
hiter capitols
France Paris
Spain Madrid

By the way, "capitol" is a building. A city is referred to as a "capital".

Dennis Williamson
thanks fixed the spelling
Lars Tackmann