Scope of Local Variables in Shell Functions

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
16
down vote

favorite












After reading 24.2. Local Variables, I thought that declaring a variable var with the keyword local meant that var's value was only accessible within the block of code delimited by the curly braces of a function.



However, after running the following example, I found out that var can also be accessed, read and written from the functions invoked by that block of code -- i.e. even though var is declared local to outerFunc, innerFunc is still able to read it and alter its value.



Run It Online



#!/usr/bin/env bash

function innerFunc()
var='new value'
echo "innerFunc: [var:$var]"


function outerFunc()
local var='initial value'

echo "outerFunc: before innerFunc: [var:$var]"
innerFunc
echo "outerFunc: after innerFunc: [var:$var]"


echo "global: before outerFunc: [var:$var]"
outerFunc
echo "global: after outerFunc: [var:$var]"


Output:



global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc`
outerFunc: before innerFunc: [var:initial value]
innerFunc: [var:new value] # `innerFunc` has access to `var` ??
outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ??
global: after outerFunc: [var:]


Q: Is that a bug in my shell (bash 4.3.42, Ubuntu 16.04, 64bit) or is it the expected behavior ?



EDIT: Solved. As noted by @MarkPlotnick, this is indeed the expected behavior.










share|improve this question























  • It is the expected behavior
    – fpmurphy1
    May 11 '16 at 17:09














up vote
16
down vote

favorite












After reading 24.2. Local Variables, I thought that declaring a variable var with the keyword local meant that var's value was only accessible within the block of code delimited by the curly braces of a function.



However, after running the following example, I found out that var can also be accessed, read and written from the functions invoked by that block of code -- i.e. even though var is declared local to outerFunc, innerFunc is still able to read it and alter its value.



Run It Online



#!/usr/bin/env bash

function innerFunc()
var='new value'
echo "innerFunc: [var:$var]"


function outerFunc()
local var='initial value'

echo "outerFunc: before innerFunc: [var:$var]"
innerFunc
echo "outerFunc: after innerFunc: [var:$var]"


echo "global: before outerFunc: [var:$var]"
outerFunc
echo "global: after outerFunc: [var:$var]"


Output:



global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc`
outerFunc: before innerFunc: [var:initial value]
innerFunc: [var:new value] # `innerFunc` has access to `var` ??
outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ??
global: after outerFunc: [var:]


Q: Is that a bug in my shell (bash 4.3.42, Ubuntu 16.04, 64bit) or is it the expected behavior ?



EDIT: Solved. As noted by @MarkPlotnick, this is indeed the expected behavior.










share|improve this question























  • It is the expected behavior
    – fpmurphy1
    May 11 '16 at 17:09












up vote
16
down vote

favorite









up vote
16
down vote

favorite











After reading 24.2. Local Variables, I thought that declaring a variable var with the keyword local meant that var's value was only accessible within the block of code delimited by the curly braces of a function.



However, after running the following example, I found out that var can also be accessed, read and written from the functions invoked by that block of code -- i.e. even though var is declared local to outerFunc, innerFunc is still able to read it and alter its value.



Run It Online



#!/usr/bin/env bash

function innerFunc()
var='new value'
echo "innerFunc: [var:$var]"


function outerFunc()
local var='initial value'

echo "outerFunc: before innerFunc: [var:$var]"
innerFunc
echo "outerFunc: after innerFunc: [var:$var]"


echo "global: before outerFunc: [var:$var]"
outerFunc
echo "global: after outerFunc: [var:$var]"


Output:



global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc`
outerFunc: before innerFunc: [var:initial value]
innerFunc: [var:new value] # `innerFunc` has access to `var` ??
outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ??
global: after outerFunc: [var:]


Q: Is that a bug in my shell (bash 4.3.42, Ubuntu 16.04, 64bit) or is it the expected behavior ?



EDIT: Solved. As noted by @MarkPlotnick, this is indeed the expected behavior.










share|improve this question















After reading 24.2. Local Variables, I thought that declaring a variable var with the keyword local meant that var's value was only accessible within the block of code delimited by the curly braces of a function.



However, after running the following example, I found out that var can also be accessed, read and written from the functions invoked by that block of code -- i.e. even though var is declared local to outerFunc, innerFunc is still able to read it and alter its value.



Run It Online



#!/usr/bin/env bash

function innerFunc()
var='new value'
echo "innerFunc: [var:$var]"


function outerFunc()
local var='initial value'

echo "outerFunc: before innerFunc: [var:$var]"
innerFunc
echo "outerFunc: after innerFunc: [var:$var]"


echo "global: before outerFunc: [var:$var]"
outerFunc
echo "global: after outerFunc: [var:$var]"


Output:



global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc`
outerFunc: before innerFunc: [var:initial value]
innerFunc: [var:new value] # `innerFunc` has access to `var` ??
outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ??
global: after outerFunc: [var:]


Q: Is that a bug in my shell (bash 4.3.42, Ubuntu 16.04, 64bit) or is it the expected behavior ?



EDIT: Solved. As noted by @MarkPlotnick, this is indeed the expected behavior.







bash shell shell-script variable function






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 19 '17 at 17:35









lesmana

13.9k105571




13.9k105571










asked May 11 '16 at 16:22









865719

181127




181127











  • It is the expected behavior
    – fpmurphy1
    May 11 '16 at 17:09
















  • It is the expected behavior
    – fpmurphy1
    May 11 '16 at 17:09















It is the expected behavior
– fpmurphy1
May 11 '16 at 17:09




It is the expected behavior
– fpmurphy1
May 11 '16 at 17:09










4 Answers
4






active

oldest

votes

















up vote
14
down vote













Shell variables have a dynamic scope. If a variable is declared as local to a function, that scope remains until the function returns.



There is an exception: in ATT ksh, if a function is defined with the standard function_name () …  syntax, then its local variables obey dynamic scoping. But if a function is defined with the ksh syntax function function_name …  then its local variable obey lexical scoping, so they are not visible in other functions called by this. But bash, mksh and zsh only have dynamic scoping.






share|improve this answer



























    up vote
    4
    down vote













    It isn't a bug, the call inside the context of the outerFunc uses that local copy of $var. The "local" in outerFunc means the global isn't changed. If you call innerFunc outside of outerFunc, then there will be a change to the global $var, but not the outerFunc's local $var. If you added "local" to innerFunc, then outerFunc's $var wouldn't be changed - in essence, there'd be 3 of them:



    • $global::var

    • $outerFunc::var

    • $innerFunc::var

    to use Perl's namespace format, sort of.






    share|improve this answer



























      up vote
      1
      down vote













      You can use a function to force local scope:



      sh_local() 
      eval "$(set)" command eval '"$@"'



      Example:



      x() 
      z='new value'
      printf 'function x, z = [%s]n' "$z"

      y()
      z='initial value'
      printf 'function y before x, z = [%s]n' "$z"
      sh_local x
      printf 'function y after x, z = [%s]n' "$z"

      printf 'global before y, z = [%s]n' "$z"
      y
      printf 'global after y, z = [%s]n' "$z"


      Result:



      global before y, z = 
      function y before x, z = [initial value]
      function x, z = [new value]
      function y after x, z = [initial value]
      global after y, z = [initial value]


      Source






      share|improve this answer



























        up vote
        0
        down vote













        In function innerFunc() the var='new value' wasn't declared as local, therefore it's available in the global scope (once the function has been called).



        Conversely, in function outFunc() the local var='initial value' was declared as local, therefore it's not available in the global scope (even if the function has been called).



        The implied behavior that's expected in the description could be achieved by declaring local var='new value in function innerFunc().



        24.2. Local Variables says all that, too.



        As others have stated, this is not a bug in the bash shell. Everything's functioning as it should.






        share|improve this answer




















          Your Answer







          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "106"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f282557%2fscope-of-local-variables-in-shell-functions%23new-answer', 'question_page');

          );

          Post as a guest






























          4 Answers
          4






          active

          oldest

          votes








          4 Answers
          4






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          14
          down vote













          Shell variables have a dynamic scope. If a variable is declared as local to a function, that scope remains until the function returns.



          There is an exception: in ATT ksh, if a function is defined with the standard function_name () …  syntax, then its local variables obey dynamic scoping. But if a function is defined with the ksh syntax function function_name …  then its local variable obey lexical scoping, so they are not visible in other functions called by this. But bash, mksh and zsh only have dynamic scoping.






          share|improve this answer
























            up vote
            14
            down vote













            Shell variables have a dynamic scope. If a variable is declared as local to a function, that scope remains until the function returns.



            There is an exception: in ATT ksh, if a function is defined with the standard function_name () …  syntax, then its local variables obey dynamic scoping. But if a function is defined with the ksh syntax function function_name …  then its local variable obey lexical scoping, so they are not visible in other functions called by this. But bash, mksh and zsh only have dynamic scoping.






            share|improve this answer






















              up vote
              14
              down vote










              up vote
              14
              down vote









              Shell variables have a dynamic scope. If a variable is declared as local to a function, that scope remains until the function returns.



              There is an exception: in ATT ksh, if a function is defined with the standard function_name () …  syntax, then its local variables obey dynamic scoping. But if a function is defined with the ksh syntax function function_name …  then its local variable obey lexical scoping, so they are not visible in other functions called by this. But bash, mksh and zsh only have dynamic scoping.






              share|improve this answer












              Shell variables have a dynamic scope. If a variable is declared as local to a function, that scope remains until the function returns.



              There is an exception: in ATT ksh, if a function is defined with the standard function_name () …  syntax, then its local variables obey dynamic scoping. But if a function is defined with the ksh syntax function function_name …  then its local variable obey lexical scoping, so they are not visible in other functions called by this. But bash, mksh and zsh only have dynamic scoping.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered May 11 '16 at 22:44









              Gilles

              515k12110231551




              515k12110231551






















                  up vote
                  4
                  down vote













                  It isn't a bug, the call inside the context of the outerFunc uses that local copy of $var. The "local" in outerFunc means the global isn't changed. If you call innerFunc outside of outerFunc, then there will be a change to the global $var, but not the outerFunc's local $var. If you added "local" to innerFunc, then outerFunc's $var wouldn't be changed - in essence, there'd be 3 of them:



                  • $global::var

                  • $outerFunc::var

                  • $innerFunc::var

                  to use Perl's namespace format, sort of.






                  share|improve this answer
























                    up vote
                    4
                    down vote













                    It isn't a bug, the call inside the context of the outerFunc uses that local copy of $var. The "local" in outerFunc means the global isn't changed. If you call innerFunc outside of outerFunc, then there will be a change to the global $var, but not the outerFunc's local $var. If you added "local" to innerFunc, then outerFunc's $var wouldn't be changed - in essence, there'd be 3 of them:



                    • $global::var

                    • $outerFunc::var

                    • $innerFunc::var

                    to use Perl's namespace format, sort of.






                    share|improve this answer






















                      up vote
                      4
                      down vote










                      up vote
                      4
                      down vote









                      It isn't a bug, the call inside the context of the outerFunc uses that local copy of $var. The "local" in outerFunc means the global isn't changed. If you call innerFunc outside of outerFunc, then there will be a change to the global $var, but not the outerFunc's local $var. If you added "local" to innerFunc, then outerFunc's $var wouldn't be changed - in essence, there'd be 3 of them:



                      • $global::var

                      • $outerFunc::var

                      • $innerFunc::var

                      to use Perl's namespace format, sort of.






                      share|improve this answer












                      It isn't a bug, the call inside the context of the outerFunc uses that local copy of $var. The "local" in outerFunc means the global isn't changed. If you call innerFunc outside of outerFunc, then there will be a change to the global $var, but not the outerFunc's local $var. If you added "local" to innerFunc, then outerFunc's $var wouldn't be changed - in essence, there'd be 3 of them:



                      • $global::var

                      • $outerFunc::var

                      • $innerFunc::var

                      to use Perl's namespace format, sort of.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered May 11 '16 at 17:16









                      afbach

                      662




                      662




















                          up vote
                          1
                          down vote













                          You can use a function to force local scope:



                          sh_local() 
                          eval "$(set)" command eval '"$@"'



                          Example:



                          x() 
                          z='new value'
                          printf 'function x, z = [%s]n' "$z"

                          y()
                          z='initial value'
                          printf 'function y before x, z = [%s]n' "$z"
                          sh_local x
                          printf 'function y after x, z = [%s]n' "$z"

                          printf 'global before y, z = [%s]n' "$z"
                          y
                          printf 'global after y, z = [%s]n' "$z"


                          Result:



                          global before y, z = 
                          function y before x, z = [initial value]
                          function x, z = [new value]
                          function y after x, z = [initial value]
                          global after y, z = [initial value]


                          Source






                          share|improve this answer
























                            up vote
                            1
                            down vote













                            You can use a function to force local scope:



                            sh_local() 
                            eval "$(set)" command eval '"$@"'



                            Example:



                            x() 
                            z='new value'
                            printf 'function x, z = [%s]n' "$z"

                            y()
                            z='initial value'
                            printf 'function y before x, z = [%s]n' "$z"
                            sh_local x
                            printf 'function y after x, z = [%s]n' "$z"

                            printf 'global before y, z = [%s]n' "$z"
                            y
                            printf 'global after y, z = [%s]n' "$z"


                            Result:



                            global before y, z = 
                            function y before x, z = [initial value]
                            function x, z = [new value]
                            function y after x, z = [initial value]
                            global after y, z = [initial value]


                            Source






                            share|improve this answer






















                              up vote
                              1
                              down vote










                              up vote
                              1
                              down vote









                              You can use a function to force local scope:



                              sh_local() 
                              eval "$(set)" command eval '"$@"'



                              Example:



                              x() 
                              z='new value'
                              printf 'function x, z = [%s]n' "$z"

                              y()
                              z='initial value'
                              printf 'function y before x, z = [%s]n' "$z"
                              sh_local x
                              printf 'function y after x, z = [%s]n' "$z"

                              printf 'global before y, z = [%s]n' "$z"
                              y
                              printf 'global after y, z = [%s]n' "$z"


                              Result:



                              global before y, z = 
                              function y before x, z = [initial value]
                              function x, z = [new value]
                              function y after x, z = [initial value]
                              global after y, z = [initial value]


                              Source






                              share|improve this answer












                              You can use a function to force local scope:



                              sh_local() 
                              eval "$(set)" command eval '"$@"'



                              Example:



                              x() 
                              z='new value'
                              printf 'function x, z = [%s]n' "$z"

                              y()
                              z='initial value'
                              printf 'function y before x, z = [%s]n' "$z"
                              sh_local x
                              printf 'function y after x, z = [%s]n' "$z"

                              printf 'global before y, z = [%s]n' "$z"
                              y
                              printf 'global after y, z = [%s]n' "$z"


                              Result:



                              global before y, z = 
                              function y before x, z = [initial value]
                              function x, z = [new value]
                              function y after x, z = [initial value]
                              global after y, z = [initial value]


                              Source







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Apr 5 '17 at 22:40









                              Steven Penny

                              2,39521635




                              2,39521635




















                                  up vote
                                  0
                                  down vote













                                  In function innerFunc() the var='new value' wasn't declared as local, therefore it's available in the global scope (once the function has been called).



                                  Conversely, in function outFunc() the local var='initial value' was declared as local, therefore it's not available in the global scope (even if the function has been called).



                                  The implied behavior that's expected in the description could be achieved by declaring local var='new value in function innerFunc().



                                  24.2. Local Variables says all that, too.



                                  As others have stated, this is not a bug in the bash shell. Everything's functioning as it should.






                                  share|improve this answer
























                                    up vote
                                    0
                                    down vote













                                    In function innerFunc() the var='new value' wasn't declared as local, therefore it's available in the global scope (once the function has been called).



                                    Conversely, in function outFunc() the local var='initial value' was declared as local, therefore it's not available in the global scope (even if the function has been called).



                                    The implied behavior that's expected in the description could be achieved by declaring local var='new value in function innerFunc().



                                    24.2. Local Variables says all that, too.



                                    As others have stated, this is not a bug in the bash shell. Everything's functioning as it should.






                                    share|improve this answer






















                                      up vote
                                      0
                                      down vote










                                      up vote
                                      0
                                      down vote









                                      In function innerFunc() the var='new value' wasn't declared as local, therefore it's available in the global scope (once the function has been called).



                                      Conversely, in function outFunc() the local var='initial value' was declared as local, therefore it's not available in the global scope (even if the function has been called).



                                      The implied behavior that's expected in the description could be achieved by declaring local var='new value in function innerFunc().



                                      24.2. Local Variables says all that, too.



                                      As others have stated, this is not a bug in the bash shell. Everything's functioning as it should.






                                      share|improve this answer












                                      In function innerFunc() the var='new value' wasn't declared as local, therefore it's available in the global scope (once the function has been called).



                                      Conversely, in function outFunc() the local var='initial value' was declared as local, therefore it's not available in the global scope (even if the function has been called).



                                      The implied behavior that's expected in the description could be achieved by declaring local var='new value in function innerFunc().



                                      24.2. Local Variables says all that, too.



                                      As others have stated, this is not a bug in the bash shell. Everything's functioning as it should.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered 24 mins ago









                                      Joseph Tingiris

                                      486




                                      486



























                                           

                                          draft saved


                                          draft discarded















































                                           


                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function ()
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f282557%2fscope-of-local-variables-in-shell-functions%23new-answer', 'question_page');

                                          );

                                          Post as a guest













































































                                          Popular posts from this blog

                                          Peggy Mitchell

                                          The Forum (Inglewood, California)

                                          Palaiologos