How to use Bash associative arrays

2 years ago 276

Command interpreters and scripting languages similar the Bash ammunition are indispensable tools of immoderate operating system. Here's however to usage successful Bash the precise almighty information structures called associative arrays, oregon hashes.

bash-script.jpg

Image: jivacore/Shutterstock

In Bash, a hash is simply a information operation that tin incorporate galore sub-variables, of the aforesaid oregon antithetic kinds, but indexes them with user-defined substance strings, oregon keys, alternatively of fixed numeric identifiers. Besides being highly flexible, hashes besides marque scripts much readable. If you request to process the areas of definite countries, for example, a syntax like:

print area_of('Germany')

would beryllium arsenic self-documenting arsenic it tin be, right?

SEE: Hiring Kit: JavaScript Developer (TechRepublic Premium)

How to make and capable Bash hashes

Bash hashes indispensable beryllium declared with the uppercase A power (meaning Associative Array), and tin past beryllium filled by listing each their key/value pairs with this syntax:

# Country areas, successful quadrate milesdeclare -A area_ofarea_of=( [Italy]="116347" [Germany]="137998" [France]="213011" [Poland]="120728" [Spain]="192476" )

The archetypal happening to announcement present is that the bid successful which the elements are declared is irrelevant. The ammunition volition conscionable disregard it, and store everything according to its ain interior algorithms. As proof, this is what happens erstwhile you retrieve those information arsenic they were stored:

print ${area_of[*]}213011 120728 137998 192476 116347print ${!area_of[*]}France Poland Germany Spain Italy

By default, the asterisk wrong the quadrate brackets extracts each and lone the values of a hash. Adding the exclamation mark, instead, retrieves the hash keys. But successful some cases determination is nary easy recognizable order.

You whitethorn besides populate a hash dynamically, by calling different programs. If you, for example, had different ammunition publication called hash-generator, that outputs each the pairs arsenic 1 decently formatted string:

#! /bin/bashprintf '[Italy]="116347" [Germany]="137998" [France]="213011" [Poland]="120728" [Spain]="192476"'calling hash-generator successful this mode from the publication that really uses the area_of hash:VALS=$( hash-generator )eval state -A area_of=( $VALS )

would capable that hash with precisely the aforesaid keys and values. Of course, the connection present is that "hash-generator" tin beryllium immoderate program, possibly overmuch much almighty than Bash, arsenic agelong arsenic it tin output information successful that format. To capable a hash with the contented of an already existing plain substance file, instead, follow these suggestions from Stack Overflow.

How to process hashes

The nonstop syntax to notation to a circumstantial constituent of a hash, oregon delete it, is this:

print ${area_of['Germany]}unset ${area_of['Germany]}

To erase a full hash, walk conscionable its sanction to unset, and past re-declare it:

unset area_ofdeclare -A area_of

The fig of key/value pairs stored into a hash is held by the peculiar adaptable called "${#HASHNAME[@]}" (don't look astatine me, I did not invent this syntax). But if each you request is to process each the elements of a hash, careless of their fig oregon interior order, conscionable travel this example:

for state successful "${!area_of[@]}"doecho "Area of $country: ${area_of[$country]}"done

whose output is:

Area of France: 213011 quadrate miles

Area of Poland: 120728 quadrate miles

Area of Germany: 137998 quadrate miles

You tin usage fundamentally the aforesaid process to make a "mirror" hash, with keys and values inverted:

declare -A country_whose_area_isfor state successful "${!area_of[@]}"; docountry_whose_area_is[${area_of[$country]}]=$countrydone

Among different things, this "mirroring" whitethorn beryllium the easiest mode to process the archetypal hash looking astatine its values, alternatively of keys.

How to benignant hashes

If hash elements are stored successful semi-random sequences, what is the astir businesslike mode to grip them successful immoderate alphanumerical order? The reply is that it depends connected what precisely should beryllium ordered and when. In the galore cases erstwhile what should beryllium sorted is lone the last output of a loop, and each is needed to bash that is simply a benignant bid close aft the closing statement:

for state successful "${!area_of[@]}"do  echo "$country: ${area_of[$country]}"done | sort

To benignant the output by cardinal (even if keys were not retrieved successful that order!):

France: 213011 quadrate miles

Germany: 137998 quadrate miles

Italy: 116347 quadrate miles.

Sorting the aforesaid lines numerically, by state area, is astir arsenic easy. Prepending the areas astatine the opening of each line:

for aa successful "${!area_of[@]}" do printf "%s|%s = %s quadrate miles\n" "${area_of[$aa]}" "$aa" "${area_of[$aa]}" done

yields lines similar these:

213011|France = 213011 sq. miles

120728|Poland = 120728 sq. miles

137998|Germany = 137998 sq. miles

that, portion inactive unsorted, present commencement with conscionable the strings connected which we privation to sort. Therefore, utilizing benignant again, but piped to the chopped bid with "|" arsenic file separator:

1 for aa successful "${!area_of_generated[@]}"2 do3 printf "%s|%s = %s quadrate miles\n" "${area_of_generated[$aa]}" "$aa" "${area_of_generated[$aa]}"4 done | benignant | chopped '-d|' -f2-

will benignant by areas and past region them, to yet nutrient the desired result:

Italy = 116347 sq. miles

Poland = 120728 sq. miles

Germany = 137998 sq. miles

Multi-level hashes

While Bash does not enactment nested, multi-level hashes, it is imaginable to emulate them with immoderate auxiliary arrays. Consider this code, that stores the areas of European regions, portion besides cataloging them by country:

1  state -a european_regions=('Bavaria' 'Lazio' 'Saxony' 'Tuscany') 2  state -a european_countries=('Italy' 'Germany') 3  state -A area_of_country_regions 4  area_of_country_regions=( [Lazio successful Italy]="5000" [Tuscany successful Italy]="6000" [Bavaria successful Germany]="9500" [Saxony successful Germany]="7200" ) 5   6  for state successful "${european_countries[@]}" 7  do 8   for portion successful "${european_regions[@]}" 9     do10       cr="$region successful $country"11       if trial "${area_of_country_regions[$cr]+isset}"12         then13         printf "Area of %-20.20s: %s\n" "$cr" "${area_of_country_regions[$cr]}"14         fi15     done16  done

The codification creates 2 mean arrays, 1 for countries and 1 for regions, positive 1 hash with composite keys that subordinate each portion to its state and emulate a two-level hash. The codification past generates each imaginable combinations of regions and countries, but lone processes existing elements of areaofcountry_regions, recognizing them with the *isset trial of enactment 11. Rough, but effective, isn't it?

Developer Essentials Newsletter

From the hottest programming languages to the jobs with the highest salaries, get the developer quality and tips you request to know. Weekly

Sign up today

Also see

Read Entire Article