Shell 脚本函数与参数传递:函数定义/返回值/作用域
一、引言
随着脚本规模增大,重复代码会成为维护噩梦。函数将可复用的逻辑封装为独立单元,是编写可维护 Shell 脚本的关键技能。
二、函数定义与调用
#!/bin/bash
函数定义与调用示例
方式一:使用 function 关键字
function say_hello {
echo "你好,欢迎学习 Shell 函数!"
}
方式二:直接使用函数名(bash 原生写法)
greet() {
echo "Hello, World!"
}
函数调用
say_hello
greet
带参数的函数调用
function print_info {
echo "姓名:$1"
echo "年龄:$2"
}
print_info "张三" 25
三、参数传递与特殊变量
#!/bin/bash
参数传递与特殊变量示例
function demo_params {
echo "函数名称:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "所有参数(字符串):$*"
echo "所有参数(数组):$@"
echo "参数个数:$#"
echo "=== 使用 $@ 遍历参数 ==="
for param in "$@"; do
echo "参数:$param"
done
echo "=== shift 操作 ==="
echo "原始 $1=$1, $2=$2"
shift
echo "shift 后 $1=$1"
}
demo_params "苹果" "香蕉" "橘子" "葡萄"
四、返回值处理
#!/bin/bash
返回值处理示例
方法一:通过 return 返回退出状态码(0-255)
function is_even {
if [ $(($1 % 2)) -eq 0 ]; then
return 0
else
return 1
fi
}
num=10
if is_even $num; then
echo "$num 是偶数"
else
echo "$num 是奇数"
fi
方法二:通过 echo 返回数据
function get_sum {
local a=$1
local b=$2
echo $((a + b))
}
result=$(get_sum 100 200)
echo "100 + 200 = $result"
方法三:通过全局变量返回数据
declare -g g_result
function get_product {
g_result=$(($1 * $2))
}
get_product 15 8
echo "15 * 8 = $g_result"
方法四:使用 nameref(bash 4+)传递变量引用
function double_value {
local -n ref=$1
ref=$((ref * 2))
}
num=50
double_value num
echo "num 翻倍后 = $num"
五、变量作用域
#!/bin/bash
变量作用域示例
全局变量
global_var="我是全局变量"
function test_scope {
# local 关键字声明局部变量
local local_var="我是局部变量"
echo "局部变量:$local_var"
# 在函数内修改全局变量
global_var="函数内修改后的值"
}
test_scope
echo "函数外全局变量:$global_var"
echo "=== 全局与局部变量同名时的处理 ==="
variable="全局"
function test_shadow {
local variable="局部"
echo "函数内:$variable"
}
test_shadow
echo "函数外:$variable"
六、函数库与脚本复用
#!/bin/bash
函数库示例
---- lib_logger.sh ----
readonly LOG_LEVEL_DEBUG=0
readonly LOG_LEVEL_INFO=1
readonly LOG_LEVEL_WARN=2
readonly LOG_LEVEL_ERROR=3
LOG_LEVEL=$LOG_LEVEL_INFO
log_debug() { [ $LOG_LEVEL -le $LOG_LEVEL_DEBUG ] && echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $*" >&2; }
log_info() { [ $LOG_LEVEL -le $LOG_LEVEL_INFO ] && echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $*" >&2; }
log_warn() { [ $LOG_LEVEL -le $LOG_LEVEL_WARN ] && echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') $*" >&2; }
log_error() { echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $*" >&2; }
---- lib_util.sh ----
command_exists() { command -v "$1" &> /dev/null; }
service_running() { systemctl is-active --quiet "$1"; }
---- 使用函数库 ----
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib_logger.sh"
source "$SCRIPT_DIR/lib_util.sh"
LOG_LEVEL=$LOG_LEVEL_DEBUG
log_info "脚本开始执行"
if command_exists docker; then
log_info "Docker 已安装"
else
log_error "Docker 未安装"
fi
七、常见问题(FAQ)
Q1: 函数内的变量会覆盖函数外的同名变量吗?
使用 local 声明的局部变量不会影响全局变量。没有 local 关键字时,函数内的赋值会直接修改全局变量。
Q2: 如何从函数返回一个大于 255 的整数?
return 语句只能返回 0-255 的退出状态码。如果需要返回大整数或字符串,应该用 echo 输出,然后通过 $(func) 捕获。
Q3: bash 函数支持默认参数值吗?
可以手动实现:param=${1:-default_value}。如果调用时未传该参数,可以用 ${1:-default} 语法提供默认值。
Q4: 函数支持递归调用吗?
bash 支持递归函数,但默认递归深度有限。递归函数示例:factorial() { [ $1 -le 1 ] && echo 1 || echo $(( $1 * $(factorial $(($1-1))) )); }
八、延伸阅读
- Linux Shell 脚本编程入门:变量、条件判断、循环基础
- Linux 环境变量与脚本调试:export/set -x 调试技巧
- Bash 常用命令与管道操作:函数库的组织与管理