Differences between revisions 1 and 2
Revision 1 as of 2007-05-02 22:50:03
Size: 3543
Editor: redondos
Comment:
Revision 2 as of 2007-05-07 19:15:30
Size: 3688
Editor: GreyCat
Comment: Why didn't this already link to #48?
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:
Sometimes it's convenient to have associative arrays, arrays indexed by a string. Perl calls them "hashes". KornShell93 already supports this kind of array: Sometimes it's convenient to have associative arrays, arrays indexed by a string. Perl calls them "hashes", while Tcl simply calls them "arrays". KornShell93 already supports this kind of array:
Line 62: Line 62:
 1. it's hard to read and to maintain
 1. the variable names must match the regular expression ^[a-zA-Z_][a-zA-Z_0-9]* , i.e. a variable name cannot contain arbitrary characters but only letters, digits, and underscores. In the example above we e.g. could not have processed the home directory of a user named {{{hong-hu}}}, because a dash '-' can be no valid part of a user name.
 1. Quoting is hard to get right. If a content (not variable name) string can contain whitespace characters, it's hard to quote it right to preserve it.
 1. It's hard to read and to maintain.
 1. The variable names must match the regular expression {{{^[a-zA-Z_][a-zA-Z_0-9]*}}} -- i.e., a variable name cannot contain arbitrary characters but only letters, digits, and underscores. In the example above we could not have processed the home directory of a user named {{{hong-hu}}}, because a dash '-' cannot be a valid part of a variable name.
 1. Quoting is hard to get right. If content strings (not variable name) can contain whitespace characters and quotes, it's hard to quote it right to preserve it.
 1. If the program handles unsanitized user input, it can be [#faq48 VERY dangerous]!

Anchor(faq6)

How can I use associative arrays or variable variables?

Sometimes it's convenient to have associative arrays, arrays indexed by a string. Perl calls them "hashes", while Tcl simply calls them "arrays". KornShell93 already supports this kind of array:

  •  # KornShell93 script - does not work with BASH
     typeset -A homedir             # Declare KornShell93 associative array
     homedir[jim]=/home/jim
     homedir[silvia]=/home/silvia
     homedir[alex]=/home/alex
     
     for user in ${!homedir[@]}     # Enumerate all indices (user names)
     do
         echo "Home directory of user $user is ${homedir[$user]}"
     done

BASH (including version 3.x) does not (yet) support them. However, we could simulate this kind of array by dynamically creating variables like in the following example:

  •  for user in jim silvia alex
     do
         eval homedir_$user=/home/$user
     done

This creates the variables

  •  homedir_jim=/home/jim
     homedir_silvia=/home/silvia
     homedir_alex=/home/alex

with the corresponding content. Note the use of the eval command, which interprets a command line not just one time like the shell usually does, but twice. In the first step, the shell uses the input homedir_$user=/home/$user to create a new line homedir_jim=/home/jim. In the second step, caused by eval, this variable assignment is executed, actually creating the variable.

Print the variables using

  •  for user in jim silvia alex
     do
         varname=homedir_$user              # e.g. "homedir_jim"
         eval varcontent='$'$varname        # e.g. "/home/jim"
         echo "home directory of $user is $varcontent"
     done

The eval line needs some explanation. In a first step the command substitution is run:

  •  eval varcontent='$'$varname

becomes

  •  eval varcontent=$homedir_jim

In a second step the eval re-evaluates the line, and converts this to

  •  varcontent=/home/jim

Before starting to use dynamically created variables, think again of a simpler approach. If it still seems to be the best thing to do, have a look at the following disadvantages:

  1. It's hard to read and to maintain.
  2. The variable names must match the regular expression ^[a-zA-Z_][a-zA-Z_0-9]* -- i.e., a variable name cannot contain arbitrary characters but only letters, digits, and underscores. In the example above we could not have processed the home directory of a user named hong-hu, because a dash '-' cannot be a valid part of a variable name.

  3. Quoting is hard to get right. If content strings (not variable name) can contain whitespace characters and quotes, it's hard to quote it right to preserve it.
  4. If the program handles unsanitized user input, it can be [#faq48 VERY dangerous]!

Here is the summary. "var" is a constant prefix, "$index" contains index string, "$content" is the string to store. Note that quoting is absolutely essential here. A missing backslash \ or a wrong type of quote (e.g. apostrophes '...' instead of quotation marks "...") can (and probably will) cause the examples to fail:

  • Set variables
    •   eval "var$index=\"$content\""    # index must only contain characters from [a-zA-Z0-9_]
  • Print variable content
    •   eval "echo \"var$index=\$$varname\""
  • Check if a variable is empty
    •   if eval "[ -z "\$var$index\" ]"
        then echo "variable is empty: $var$index"
        fi

You've seen the examples. Now maybe you can go a step back and consider using AWK associative arrays, or a multi-line environment variable instead of dynamically created variables.

BashFAQ/006 (last edited 2023-04-14 06:52:11 by ormaaj)