How to raise and take care of shell scripts: Variables

Scope of variables

A variable defined with VAR=wert is valid within this (and only this) shell. If you create a subshell, it's no longer known. To make it known in a subshell, you have to export it:

  jan@jack:~/tmp> VAR=1
  jan@jack:~/tmp> sh -c "echo $VAR"  # $VAR is expanded in the current shell
  1
  jan@jack:~/tmp> sh -c 'echo $VAR'  # $VAR is expanded in the subshell

  jan@jack:~/tmp> export VAR         # Export
  jan@jack:~/tmp> sh -c 'echo $VAR'  # now $VAR is known in the subshell
  1
  jan@jack:~/tmp> VAR=2
  jan@jack:~/tmp> sh -c 'echo $VAR'  # when modifying the value no new export is necessary
  2

What never works: Return modified variable values from a subshell back to the parent. Often this is forgotten when feeding a while loop using a pipe - the pipe creates a subshell (see Sub-Shells):

  jan@jack:~/tmp> sh -c 'VAR=3'
  jan@jack:~/tmp> echo $VAR
  2
  jan@jack:~/tmp> ls | while read x; do VAR=$x; done
  jan@jack:~/tmp> echo $VAR
  2

There are two ways to return a new value back to the parent process: Output the new value on standard output STDOUT and catch it in the calling process using command substitution or obstain from using subshells (see the next chapters for that):

  jan@jack:~/tmp> VAR=`sh -c 'VAR=$((VAR + 1)); echo $VAR'`
  jan@jack:~/tmp> echo $VAR
  3

All shell variables per default are globally defined. There's a trap, especially when you use recursively working functions. A small, almost seamless example:

  function recursive {
    # a counter
    number=0
    # depth in recursion; it's a functional argument, I increment
    depth=`expr $1 + 1`
    # loop, as long as $number is less than 3 and depth is less than 3
    while test $number -le 2 -a $depth -le 2
    do
      # output values
      echo "number=$number depth=$depth"
      # next recursion depth
      recursive $depth
      # Trap! $depth has reached 2, because of it's global scope
      # and was incremented in every recursive call
      number=`expr $number + 1`
      # exit loop, because exit condition is reached. Round with $number = 1 never happens
    done
  }

You can avoid this problem in the bash, when you use the local definition of the variables:

  function recursive {
    # a counter
    local number=0
    # depth in recursion; it's a functional argument, I increment
    local depth=`expr $1 + 1`
    ...
  }