8.2. Local vs Global#
8.2.1. Common Pitfalls#
1. Forgetting local and accidentally modifying globals
# Bad: Silently changes global state
process_data() {
temp=$1 # Overwrites global temp
result=$temp # Sets global result
}
# Good: Protect the global scope
process_data() {
local temp=$1
local result=$temp
}
2. Relying on variable scope instead of being explicit
# Fragile: Works now but risky
func_a() {
x=10
func_b
echo $x # Depends on func_b not changing x
}
# Better: Be explicit
func_a() {
local x=10
func_b
echo $x # Now safe: func_b can't affect x
}
3. Shadowing without realizing it
# Surprising behavior
name="global"
change_name() {
local name="local" # Shadowing not obvious
}
change_name
echo $name # Still "global" - might surprise the reader
8.2.2. Real-World Example: Encapsulation#
#!/bin/bash
# Global configuration
username="admin"
password=""
# Function that uses local variables for safety
validate_credentials() {
local input_user=$1
local input_pass=$2
local temp_hash
# temp_hash is local to this function only
temp_hash=$(echo -n "$input_pass" | md5sum | cut -d' ' -f1)
if [[ "$input_user" == "$username" ]]; then
echo "User found"
return 0
else
echo "User not found"
return 1
fi
}
# Initialize password (global)
set_password() {
password=$1 # Sets global password
}
# Call function
set_password "secret123"
validate_credentials "admin" "secret123"
Best practice: Use local variables in functions to avoid accidentally modifying global state.
8.2.3. Nested Function Calls and Scope#
Local variables are visible to functions called from within the function.
8.2.3.1. Scope Chain#
#!/bin/bash
outer_var="outer"
func_a() {
local func_a_var="in func_a"
echo "func_a: outer_var=$outer_var, func_a_var=$func_a_var"
func_b
}
func_b() {
# Can see outer_var (global) and func_a_var (from caller)
echo "func_b: outer_var=$outer_var, func_a_var=$func_a_var"
local func_b_var="in func_b"
func_c
}
func_c() {
# Can see outer_var and func_a_var, but NOT func_b_var
echo "func_c: outer_var=$outer_var, func_a_var=$func_a_var"
# func_b_var is not visible here
}
func_a
# Output:
# func_a: outer_var=outer, func_a_var=in func_a
# func_b: outer_var=outer, func_a_var=in func_a
# func_c: outer_var=outer, func_a_var=in func_a
Local variables from parent functions are visible, but siblings’ locals are not.
8.2.4. Shadowing: Local Variables with Same Names#
When a function declares a local variable with the same name as a global, the local shadows the global within that function.
8.2.4.1. Shadowing Example#
#!/bin/bash
name="Alice"
process() {
local name="Bob" # Shadows the global 'name'
echo "In function: $name"
}
echo "Before: $name"
process
echo "After: $name"
# Output:
# Before: Alice
# In function: Bob
# After: Alice
# The global 'name' is unchanged
8.2.5. Local Variables with local Keyword#
Use the local keyword to create function-scoped variables. Local variables are visible only within the function and any functions it calls.
8.2.5.1. Local Variable Scope#
#!/bin/bash
counter=0 # Global
increment() {
local counter=100 # Local: shadows the global
counter=$((counter + 1))
echo "In function: counter=$counter"
}
echo "Before: counter=$counter"
increment
echo "After: counter=$counter"
# Output:
# Before: counter=0
# In function: counter=101
# After: counter=0
The local declaration creates a variable that exists only within the function’s scope.
8.2.6. Global Variables and Functions#
In bash, variables are global by default. Any variable set inside a function is accessible everywhere in the script.
8.2.6.1. Global Variable Behavior#
#!/bin/bash
# Global variable
message="Global message"
show_message() {
echo "In function: $message"
message="Function changed this"
}
echo "Before: $message"
show_message
echo "After: $message"
# Output:
# Before: Global message
# In function: Global message
# After: Function changed this
This can lead to unexpected behavior: the function modified the global variable.