12

I am learning shell scripting through some online tutorials and I came to the following script that declares differences of global and local variables.

#!/bin/bash
# Experimenting with variable scope
var_change () {
  local var1='local 1'
  echo Inside function: var1 is $var1 : var2 is $var2
  var1='changed again'
  var2='changed again'
}

var1='global 1'
var2='global 2'

echo Before function call: var1 is $var1 : var2 is $var2

var_change

echo After function call: var1 is $var1 : var2 is $var2

And the output is:

Before function call: var1 is global 1 : var2 is global 2

Inside function: var1 is local 1 : var2 is global 2

After function call: var1 is global 1 : var2 is changed again

My Question...

Why is var1 after the function call "global 1" instead of "changed again"? Can someone explain?

3 Answers 3

19

var1 is declared local in the function. So during the execution of the function there are two variables named var1: the global one and the local one; but the function can only "see" the local one (the local one "shadows" the global one). So inside the function anything that you do to var1 is done to the local variable; the global var1 is not touched at all.

3

One way to think of it is to imagine that the local var1="local 1" has the effect of saving the current value of var1, with a promise that at the end of the function it will be restored, and then setting it to "local 1". With this mental model you can then think of all variables as global, and variables being restored at the end of functions.

The example would have been better if instead of calling echo both inside the function and outside it had called another function which had outputted var.

bash$ show(){ printf "   The value of %s in %s is '%s'\n" $1 $2 ${!1} ; }
bash$ bar(){ show v1 bar_$1 ; }
bash$ foo(){ show v1 before_foo ; local v1 ; show v1 after_local ; \ 
               v1="changed"; show v1 after_change ; bar via_foo ; }
bash$ v1="global"
bash$ show v1 global_scope
   The value of v1 in global_scope is 'global'
bash$ foo
   The value of v1 in before_foo is 'global'
   The value of v1 in after_local is ''
   The value of v1 in after_change is 'changed'
   The value of v1 in bar_via_foo is 'changed'
bash$ bar direct
   The value of v1 in bar_direct is 'global'
bash$ show v1 global_scope
   The value of v1 in global_scope is 'global'

Here you can see in the call to bar from inside foo picks up the value of v1 that was established by foo.

A web search for dynamic scope vs lexical scope might help.

1
  • "At the end of the function it will be restored", this makes my mind clear! Thanks Commented Sep 24, 2017 at 4:00
3

In Bash, local variables must be explicitly called, or else they will be treated as global. Even inside of functions (which is where the scope applies).

And, whatever scope was last set on a variable--either local, via an explicit declaration of the word local, or global via omission--will be what is returned at the time that it is called via echo.

So, in your example, after the function is called, local scope is set on var1, so any changes to this variable do not persist outside the function. But global stays set on var2, so changes to this variable do.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .