XXX Local Variables¶
What makes a variable *local*?
- local variables
- A variable declared as local is one that is visible only within the block of code in which it appears. It has local scope. In a function, a local variable has meaning only within that function block. [1]
Exemple 12. Local variable visibility¶
#!/bin/bash # ex62.sh: Global and local variables inside a function. func () { local loc_var=23 # Declared as local variable. echo # Uses the 'local' builtin. echo "\"loc_var\" in function = $loc_var" global_var=999 # Not declared as local. # Therefore, defaults to global. echo "\"global_var\" in function = $global_var" } func # Now, to see if local variable "loc_var" exists outside the functio n. echo echo "\"loc_var\" outside function = $loc_var" # $loc_var outside function = # No, $loc_var not visible glo bally. echo "\"global_var\" outside function = $global_var" # $global_var outside function = 999 # $global_var is visible globa lly. echo exit 0 # In contrast to C, a Bash variable declared inside a function #+ is local ONLY if declared as such.Caution Before a function is called, all variables declared within the function are invisible outside the body of the function, not just those explicitly declared as local.
#!/bin/bash func () { global_var=37 # Visible only within th e function block # + before the function ha s been called. } # END OF FUNCTION echo "global_var = $global_var" # global_ var = # Functi on "func" has not yet be en called, #+ so $gl obal_var is not visible he re. func echo "global_var = $global_var" # global_ var = 37 # Has bee n set by function call.Note
As Evgeniy Ivanov points out, when declaring and setting a local variable in a single command, apparently the order of operations is to first set the variable, and only afterwards restrict it to local scope. This is reflected in the return value.
#!/bin/b ash echo "== OUTSIDE Functi on (global)==" t=$(exit 1) echo $? # 1 # As expe cted. echo function 0 () { echo "== INSIDE Functio n==" echo "Gl obal" t0=$(exi t 1) echo $? # 1 # As expe cted. echo echo "Lo cal declared & assigned in s ame command." local t1 =$(exit 1) echo $? # 0 # Unexpec ted! # Appar ently, the var iable assignme nt takes place before #+ the l ocal declarati on. #+ The r eturn value is for the latte r. echo echo "Lo cal declared, then assigned (separate comm ands)." local t2 t2=$(exi t 1) echo $? # 1 # As expe cted. } function 0
24.2.1. Local variables and recursion.¶
Recur sion is an intere sting and someti mes useful form of self- refere nce. Herbe rt Mayer _ define s it as ”. . . expres sing an algori thm by using a simple r versio n of that same algori thm . . .”
Consid er a defini tion define d in terms of itself , `[2] < localv ar.htm l#FTN. AEN186 07>`__ an expres sion implic it in its own expres sion, `[3] < localv ar.htm l#FTN. AEN186 10>`__ a snake swallo wing its own tail, `[4] < localv ar.htm l#FTN. AEN186 14>`__ or . . . a functi on that calls itself . `[5] < localv ar.htm l#FTN. AEN186 17>`__
Exam ple 24-13. Demons tratio n of a simple recurs ive functi on
#!/bin
/bash
# recu
rsion-
demo.s
h
# Demo
nstrat
ion of
recur
sion.
RECURS
IONS=9
# H
ow man
y time
s to r
ecurse
.
r_coun
t=0
# M
ust be
globa
l. Why
?
recurs
e ()
{
var=
"$1"
whil
e [ "$
var" -
ge 0 ]
do
ec
ho "Re
cursio
n coun
t = "$
r_coun
t" +-
+ \$v
ar = "
$var""
((
var--
)); (
( r_co
unt++
))
re
curse
"$var"
# F
unctio
n call
s itse
lf (re
curses
)
done
#+ u
ntil w
hat co
nditio
n is m
et?
}
recurs
e $REC
URSION
S
exit $
?
**Exam
ple
24-14.
Anothe
r
simple
demons
tratio
n**
+-----
------
------
------
------
------
------
------
------
------
------
------
---+
.. c
ode::
PROGRA
MLISTI
NG
#!/bin
/bash
# recu
rsion-
def.sh
# A sc
ript t
hat de
fines
"recur
sion"
in a r
ather
graphi
c way.
RECURS
IONS=1
0
r_coun
t=0
sp=" "
define
_recur
sion (
)
{
((r_
count+
+))
sp="
$sp""
"
echo
-n "$
sp"
echo
"\"Th
e act
of rec
urring
... \
"" #
Per 1
913 We
bster'
s dict
io
nary
.
whil
e [ $r
_count
-le $
RECURS
IONS ]
do
de
fine_r
ecursi
on
done
}
echo
echo "
Recurs
ion: "
define
_recur
sion
echo
exit $
?
Local variables are a useful tool for writing recursive code, but this practice generally involves a great deal of computational overhead and is definitely not recommended in a shell script. [6]
Exemple 15. Recursion, using a local variable¶
#!/bin/bash # factorial # --------- # Does bash permit recursion? # Well, yes, but... # It's so slow that you gotta have rocks in your head to try it. MAX_ARG=5 E_WRONG_ARGS=85 E_RANGE_ERR=86 if [ -z "$1" ] then echo "Usage: `basename $0` number" exit $E_WRONG_ARGS fi if [ "$1" -gt $MAX_ARG ] then echo "Out of range ($MAX_ARG is maximum)." # Let's get real now. # If you want greater range than this, #+ rewrite it in a Real Programming Language. exit $E_RANGE_ERR fi fact () { local number=$1 # Variable "number" must be declared as local, #+ otherwise this doesn't work. if [ "$number" -eq 0 ] then factorial=1 # Factorial of 0 = 1. else let "decrnum = number - 1" fact $decrnum # Recursive function call (the function calls its elf). let "factorial = $number * $?" fi return $factorial } fact $1 echo "Factorial of $1 is $?." exit 0
Also see Example A-15 for an example of recursion in a script. Be aware that recursion is resource-intensive and executes slowly, and is therefore generally not appropriate in a script.
However, as Thomas Braunberger points out, a local variable declared in a function is also visible to functions called by the parent function.
#!/bin/bash function1 () { local func1var=20 echo "Within function1, \$func1var = $func1var." function2 } function2 () { echo "Within function2, \$func1var = $func1var." } function1 exit 0 # Output of the script: # Within function1, $func1var = 20. # Within function2, $func1var = 20.
This is documented in the Bash manual:
“Local can only be used within a function; it makes the variable name have a visible scope restricted to that function and its children.” [emphasis added] The ABS Guide author considers this behavior to be a bug.
Otherwise known as redundancy.
Otherwise known as tautology.
Otherwise known as a metaphor.
Otherwise known as a recursive function.
Too many levels of recursion may crash a script with a segfault.
#!/bin/bash # Warning: Running this script could possibly lock up your system! # If you're lucky, it will segfault before using up all available m emory. recursive_function () { echo "$1" # Makes the function do something, and hastens the seg fault. (( $1 < $2 )) && recursive_function $(( $1 + 1 )) $2; # As long as 1st parameter is less than 2nd, #+ increment 1st and recurse. } recursive_function 1 50000 # Recurse 50,000 levels! # Most likely segfaults (depending on stack size, set by ulimit -m) . # Recursion this deep might cause even a C program to segfault, #+ by using up all the memory allotted to the stack. echo "This will probably not print." exit 0 # This script will not exit normally. # Thanks, Stéphane Chazelas.