This is an old revision of the document!


The local builtin command

Synopsis

Description

TODO: Describe Bash scope rules in some detail. Point pages like The declare builtin command and those dealing with functions here for more details on locals and dynamic scope. This wiki could use a dedicated article about functions. Not sure how to organize all this information yet. Help if you can. ^_^

The most important thing to know about variable scope in Bash is that the variables visible from within the body of a function are always the same as those which are visible at the time a function is called. Two equivalent ways of stating how this works:

  • A called function sees a cascading view of all variables out to the first caller which declared a local by a given name. Variable scope works much like subclass polymorphism in this way, or CSS inheritance.

Or alternatively:

  • All descendant callees of a function see locals defined in the scope of the caller until another function defines a local of the same name, whose callees and all further descendents will then see the new variable.

This differs from the majority of other languages except those with so-called dynamic scope, though shell functions are so vastly unconventional in other ways that it's difficult to judge whether this behavior is good or bad by contrast to the conventions of other languages. If a function doesn't take care to locally define the variables used by commands then the value of any given variable can differ depending on the context from which it is called. Alternatively, almost all gotchas regarding use of global variables in most languages also apply at least equally to Bash, if not moreso, as Bash lacks namespaces and a powerful type system.

This discussion inevitably brings up questions about closures, first-class-functions, higher-order-functions, continuations, function-objects, and the like. The answer is that these concepts are rarely applicable to Bash for the aforementioned reason that "functions" are just distantly reminiscent of what one would typically call a "conventional" function. Function definitions can't be nested in the usual sense, nor can they be passed around to, or returned from functions either as objects or by reference.

Examples

Notice that nesting function definitions doesn't impact the results.

$ ( f() { local x=2; g() { echo "$x"; }; }; f; g )

$ ( f() { local x=2; g() { echo "$x"; }; g; }; f )
2
$ ( g() { echo "$x"; }; f() { local x=2; g; }; f )
2

"inheritance-like" behavior. Notice "f" doesn't care that a global "x" is in the scope of the definition. Only "call-time" matters.

x=0

f() ((
    x++
))

g() {
    local x
    f
    echo "$x"
}

g         # prints 1
echo "$x" # prints 0

Portability considerations

  • In Bash, Zsh, and Mksh, locals referenced as arithmetic variables become local at the start of the typeset command (and are therefore always zero), while parameter expansions have the value of the next-outermost scope. The only exception is the original Ksh.

# ksh93 only. Infinite recursion in others.
$ f() { typeset -i n=${1:---n}; if ((n)); then printf $n; f; fi }; f 5
54321

# Bash et al.
$ f() { typeset -i n=${1:-$n-1}; if ((n)); then printf -- $n; f; fi }; f 5
54321

  • local is not specified by POSIX. Additionally, local is Bash-only. It is identical to The declare builtin command in every way, and takes all the same options, except that usage outside of a function is an error. Using declare within a function has the same effect as local unless the -g option is given. typeset is technically more portable than both local and declare, but labeled as "depreciated" in the Bash manpage.
  • POSIX does not specify function local variables and their behavior is therefore not formally defined and often largely undocumented. The Korn shell and derivatives including Bash and Zsh thankfully mostly agree on semantics (when using the "POSIX-style" function definition syntax), and overload the typeset builtin (or declare and local) to declare variables as local.

See also

Discussion

Enter your comment. Wiki syntax is allowed: