函数:定义、参数、返回值 (Functions)
章节概述
本章讲解 Bash 函数的定义与调用、参数传递机制、返回值处理、局部变量作用域、递归函数,以及与 C 函数的对比。
核心理念:Bash 函数没有参数类型和返回类型——一切都是字符串和退出码。真正的”返回值”通过 echo 输出,退出码只表示成功/失败。
第1节:函数定义的两种语法
# 语法1(推荐)
function greet {
echo "Hello, $1!"
}
# 语法2(POSIX 兼容)
greet() {
echo "Hello, $1!"
}
# 调用
greet "World" # 输出: Hello, World!两种语法对比:
| 语法 | POSIX 兼容 | 带 function 关键字 |
|---|---|---|
func() { } | 是 | 否 |
function func { } | 否 | 是 |
建议:优先使用
func() { }写法,兼容性更好。
第2节:参数传递 9
show_args() {
echo "脚本名: $0"
echo "参数1: $1"
echo "参数2: $2"
echo "参数3: $3"
echo "参数个数: $#"
}
show_args "hello" 42 "world"参数相关变量:
| 变量 | 含义 |
|---|---|
$1~$9 | 第1到第9个参数 |
${10} | 第10个及以后(需花括号) |
$# | 参数个数 |
$@ | 所有参数(分别引用) |
$* | 所有参数(作为整体) |
$0 | 脚本/函数名 |
# $@ vs $* 的区别
demo() {
echo "=== \$@ ==="
for arg in "$@"; do echo " [$arg]"; done
echo "=== \$* ==="
for arg in "$*"; do echo " [$arg]"; done
}
demo "hello world" "foo bar"
# $@: 分别引用 → ["hello world"] ["foo bar"]
# $*: 作为整体 → ["hello world foo bar"]第3节:return vs echo
# return 只能返回退出码(0-255)
is_root() {
[ "$(id -u)" -eq 0 ] && return 0 || return 1
}
is_root && echo "是 root" || echo "非 root"
# 真正的"返回值"通过 echo
add() {
echo $(( $1 + $2 ))
}
result=$(add 3 5)
echo "$result" # 8return vs echo 对比:
| 方式 | 返回类型 | 范围 | 用途 |
|---|---|---|---|
return N | 退出码 | 0-255 | 状态标志(成功/失败) |
echo | 字符串 | 任意 | 实际数据 |
最佳实践:用
return表示成功/失败,用echo返回数据,通过$()捕获。
第4节:局部变量 local
counter=0
increment() {
local counter=0 # 局部变量,不影响全局
((counter++))
echo "函数内: $counter"
}
increment # 函数内: 1
echo "函数外: $counter" # 0(未受影响)不使用 local 的陷阱:
x=10
modify() {
x=999 # 修改了全局变量!
}
modify
echo $x # 999
# ✓ 用 local 避免污染
x=10
safe_modify() {
local x=999
echo "函数内: $x"
}
safe_modify # 函数内: 999
echo $x # 10(全局未受影响)规则:函数内始终用
local声明所有局部变量。
第5节:递归函数
# 阶乘
factorial() {
local n=$1
if [ $n -le 1 ]; then
echo 1
else
local prev=$(factorial $((n - 1)))
echo $((n * prev))
fi
}
echo "5! = $(factorial 5)" # 120C 对比:
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}注意:Bash 递归深度有限(默认约 1000),深层递归应考虑循环替代。
第6节:函数作为参数
# 高阶函数:将函数名作为参数
apply() {
local func=$1
shift
"$func" "$@"
}
greet() { echo "Hello, $1!"; }
farewell() { echo "Goodbye, $1!"; }
apply greet "Alice" # Hello, Alice!
apply farewell "Bob" # Goodbye, Bob!第7节:函数库与 source
# utils.sh - 公共函数库
log_info() { echo "[INFO] $*"; }
log_error() { echo "[ERROR] $*" >&2; }
die() { log_error "$@"; exit 1; }
# main.sh - 主脚本
source ./utils.sh
log_info "脚本开始"
[ -f "$1" ] || die "文件不存在: $1"
log_info "处理完成"source vs 执行:
| 方式 | 作用域 | 用途 |
|---|---|---|
source file.sh | 当前 shell | 加载函数、变量 |
bash file.sh | 子 shell | 独立执行 |
第8节:课后练习
- 编写函数
max,接收两个参数返回较大值 - 用递归实现斐波那契数列函数
- 创建函数库并用 source 加载
相关章节: