Shell 中的变量默认是全局的,在脚本的任何地方都能访问。这在函数里可能会带来问题——函数里的变量可能意外修改外部的变量。local 关键字可以解决这个问题。
默认情况下,Shell 变量都是全局的:
#!/bin/bash
name="外部变量"
show_name() {
echo "函数内:$name"
name="函数内修改"
}
echo "调用前:$name"
show_name
echo "调用后:$name"
运行结果:
调用前:外部变量
函数内:外部变量
调用后:函数内修改
函数里对 name 的修改影响到了外部的变量。如果只是想在函数里用个临时变量,这就会出问题。
用 local 关键字声明的变量是局部的,只在当前函数内有效:
#!/bin/bash
name="外部变量"
show_name() {
local name="局部变量"
echo "函数内:$name"
}
echo "调用前:$name"
show_name
echo "调用后:$name"
运行结果:
调用前:外部变量
函数内:局部变量
调用后:外部变量
函数里的 name 是局部变量,和外部的 name 互不影响。养成好习惯,函数里的临时变量都用 local 声明。
局部变量只在定义它的函数及其子函数中有效:
outer() {
local x=10
echo "outer: $x"
inner
echo "outer after inner: $x"
}
inner() {
echo "inner: $x"
x=20
}
outer
运行结果:
outer: 10
inner: 10
outer after inner: 20
inner 函数能访问 outer 的局部变量 x,而且修改会影响 outer。这是因为 inner 是在 outer 内部调用的。
如果 inner 是独立定义的,情况就不一样了:
#!/bin/bash
inner() {
local x=30
echo "inner: $x"
}
outer() {
local x=10
echo "outer: $x"
inner
echo "outer after inner: $x"
}
outer
运行结果:
outer: 10
inner: 30
outer after inner: 10
inner 自己声明了 local x,和 outer 的 x 是两个不同的变量。
func_a() {
local var_a="A的变量"
echo "func_a: $var_a"
func_b
echo "func_a 调用后: $var_a"
}
func_b() {
echo "func_b 尝试访问: $var_a"
var_a="B修改了"
}
func_a
运行结果:
func_a: A的变量
func_b 尝试访问: A的变量
func_b 可以访问并修改
func_a 调用后: B修改了
func_b 没有用 local 声明 var_a,所以它访问的是 func_a 的局部变量。这是个容易踩的坑。
函数内的变量都用 local:除非确实需要修改外部变量,否则一律用 local。
calculate() {
local sum=0
local i
for i in "$@"; do
sum=$((sum + i))
done
echo $sum
}
需要共享的变量用明确的名字:如果多个函数需要共享某个变量,给它一个清晰的名字,并在注释中说明。
# 全局变量:记录错误数量
ERROR_COUNT=0
report_error() {
echo "错误:$1"
ERROR_COUNT=$((ERROR_COUNT + 1))
}
避免变量名冲突:局部变量可以用简短的名字,全局变量最好加上前缀。
#!/bin/bash
MYAPP_DEBUG=0
MYAPP_LOG_FILE="/var/log/myapp.log"
process() {
local debug=$MYAPP_DEBUG
local file=$MYAPP_LOG_FILE
# ...
}