Differences between revisions 4 and 5
Revision 4 as of 2007-11-30 02:53:27
Size: 4098
Editor: GreyCat
Comment: change internal links
Revision 5 as of 2008-05-08 23:20:52
Size: 4098
Editor: GreyCat
Comment: clean up
Deletions are marked like this. Additions are marked like this.
Line 8: Line 8:
 1. If the program handles unsanitized user input, it can be [:BashFAQ#faq48:VERY dangerous]!  1. If the program handles unsanitized user input, it can be [:BashFAQ/048:VERY dangerous]!
Line 12: Line 12:
  # Bash
Line 20: Line 21:
  # Bash
Line 26: Line 28:
  # Bash
Line 30: Line 33:
Another is to use Bash's {{{printf -v}}} (only available in [:BashFAQ#faq61:recent versions]): Another is to use Bash's {{{printf -v}}} (only available in [:BashFAQ/061:recent versions]):
Line 32: Line 35:
  # Bash 3.1 or higher
Line 48: Line 52:
  # Portable code.   # Bourne
Line 56: Line 60:
Unfortunately, for shells other than Bash, there is no syntax for ''evaluating'' a referenced variable. You would have to use [:BashFAQ#faq48:eval], which means you would have to undergo extreme measures to sanitize your data to avoid catastrophe. Unfortunately, for shells other than Bash, there is no syntax for ''evaluating'' a referenced variable. You would have to use [:BashFAQ/048:eval], which means you would have to undergo extreme measures to sanitize your data to avoid catastrophe.
Line 58: Line 62:
Sometimes it's convenient to have associative arrays, arrays indexed by a string. Awk has associative arrays. Perl calls them "hashes", while Tcl simply calls them "arrays". KornShell93 supports this kind of array: Sometimes it's convenient to have associative arrays, arrays indexed by a string. Awk has associative arrays. Perl calls them "hashes", while Tcl simply calls them "arrays". [:KornShell:ksh93] supports this kind of array:
Line 61: Line 65:
 # KornShell93 script - does not work with BASH
 typeset -A homedir # Declare KornShell93 associative array
 # ksh93
 typeset -A homedir # Declare ksh93 associative array
Line 72: Line 76:
BASH (including version 3.x) does not support them, unfortunately. Either use [:BashFAQ#faq48:eval] after sanitizing your data, or switch to awk, perl, ksh93, tcl, etc. BASH (including version 3.x) does not support them, unfortunately. Either use [:BashFAQ/048:eval] after sanitizing your data, or switch to awk, perl, ksh93, tcl, etc.

Anchor(faq6)

How can I use variable variables (indirect variables, pointers, references) or associative arrays?

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. We cannot have a variable's name contain Unix usernames; consider a user named hong-hu. 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 [:BashFAQ/048:VERY dangerous]!

Bash (but not Korn shell, POSIX or Bourne shell) allows you to expand a parameter indirectly -- that is, one variable may contain the name of another variable:

  •   # Bash
      realvariable=contents
      ref=realvariable
      echo "${!ref}"   # prints the contents of the real variable

This works for evaluating, but not for assigning a value. In order to assign a value "through" a reference (or pointer, or indirect variable, or whatever you want to call it -- I'm going to use "ref" from now on), you have to resort to tricks.

One such trick is to use read and Bash's here string syntax:

  •   # Bash
      ref=realvariable
      read $ref <<< "contents"
      # realvariable now contains the string "contents"

This works equally well with Bash array variables too:

  •   # Bash
      aref=realarray
      read -a $aref <<< "words go into array elements"
      echo "${realarray[1]}"   # prints "go"

Another is to use Bash's printf -v (only available in [:BashFAQ/061:recent versions]):

  •   # Bash 3.1 or higher
      ref=realvariable
      printf -v $ref "contents"

The printf -v trick is handy if your contents aren't a constant string, but rather, something dynamically generated. You can use all of printf's formatting capabilities.

Yet another is Korn shell's typeset or Bash's declare. These are roughly equivalent to each other. Both of them cause a variable to become locally scoped to a function, if used inside a function; but if used outside a function, they can substitute for read in this case:

  •   # Korn shell:
      typeset $ref="contents"
    
      # Bash:
      declare $ref="contents"

If you aren't using Bash or Korn shell, you can still do assignments to referenced variables using here document syntax:

  •   # Bourne
      ref=realvariable
      read $ref <<EOF
      contents
      EOF

Remember that, when using a here document, if the sentinel word (EOF in our example) is unquoted, then parameter expansions will be performed inside the body. If the sentinel is quoted, then parameter expansions are not performed. Use whichever is more convenient for your task.

Unfortunately, for shells other than Bash, there is no syntax for evaluating a referenced variable. You would have to use [:BashFAQ/048:eval], which means you would have to undergo extreme measures to sanitize your data to avoid catastrophe.

Sometimes it's convenient to have associative arrays, arrays indexed by a string. Awk has associative arrays. Perl calls them "hashes", while Tcl simply calls them "arrays". [:KornShell:ksh93] supports this kind of array:

  •  # ksh93
     typeset -A homedir             # Declare ksh93 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 support them, unfortunately. Either use [:BashFAQ/048:eval] after sanitizing your data, or switch to awk, perl, ksh93, tcl, etc.

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