函数基础 #

一、函数定义 #

1.1 基本语法 #

bash
# 方式一:使用function关键字
function 函数名() {
    命令
}

# 方式二:省略function关键字
函数名() {
    命令
}

# 方式三:单行定义
函数名() { 命令; }

1.2 简单示例 #

bash
#!/bin/bash

# 定义函数
hello() {
    echo "Hello, World!"
}

# 调用函数
hello

# 带参数的函数
greet() {
    echo "你好, $1!"
}

greet "张三"
greet "李四"

1.3 函数定义位置 #

bash
#!/bin/bash

# 函数必须先定义后使用
# 错误示例:
# hello  # 此时函数未定义,会报错

# 正确示例:
hello() {
    echo "Hello!"
}

hello  # 正确调用

# 函数可以放在脚本开头或单独文件中

二、函数调用 #

2.1 基本调用 #

bash
#!/bin/bash

show_info() {
    echo "当前用户: $USER"
    echo "当前目录: $(pwd)"
    echo "当前时间: $(date)"
}

# 直接调用
show_info

# 在命令替换中调用
info=$(show_info)
echo "$info"

# 在条件中调用
if show_info; then
    echo "函数执行成功"
fi

2.2 在其他脚本中调用 #

bash
#!/bin/bash

# functions.sh - 函数库文件
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

error() {
    echo "[ERROR] $*" >&2
}
bash
#!/bin/bash

# main.sh - 主脚本
source functions.sh  # 加载函数库

log "程序启动"
error "发生错误"

三、函数参数 #

3.1 位置参数 #

bash
#!/bin/bash

# 函数参数使用位置参数
show_args() {
    echo "第一个参数: $1"
    echo "第二个参数: $2"
    echo "所有参数: $@"
    echo "参数个数: $#"
}

show_args "apple" "banana" "cherry"

# 输出:
# 第一个参数: apple
# 第二个参数: banana
# 所有参数: apple banana cherry
# 参数个数: 3

3.2 参数处理 #

bash
#!/bin/bash

# 默认参数
greet() {
    local name="${1:-匿名}"
    echo "你好, $name!"
}

greet "张三"  # 输出: 你好, 张三!
greet        # 输出: 你好, 匿名!

# 参数验证
process_file() {
    local file="$1"
    
    if [[ -z "$file" ]]; then
        echo "错误: 请指定文件名" >&2
        return 1
    fi
    
    if [[ ! -f "$file" ]]; then
        echo "错误: 文件 $file 不存在" >&2
        return 1
    fi
    
    echo "处理文件: $file"
    # 处理逻辑
}

process_file "test.txt"

3.3 遍历参数 #

bash
#!/bin/bash

# 遍历所有参数
print_all() {
    for arg in "$@"; do
        echo "参数: $arg"
    done
}

print_all "one" "two" "three"

# 使用shift处理参数
process_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -f|--file)
                file="$2"
                shift 2
                ;;
            -v|--verbose)
                verbose=true
                shift
                ;;
            *)
                echo "未知参数: $1"
                shift
                ;;
        esac
    done
    
    echo "文件: ${file:-未指定}"
    echo "详细模式: ${verbose:-false}"
}

process_args -f test.txt -v

四、函数返回值 #

4.1 使用return #

bash
#!/bin/bash

# 返回状态码
is_even() {
    local num=$1
    
    if (( num % 2 == 0 )); then
        return 0  # 成功
    else
        return 1  # 失败
    fi
}

# 使用返回值
if is_even 10; then
    echo "10是偶数"
fi

if ! is_even 7; then
    echo "7不是偶数"
fi

# 获取返回值
is_even 10
echo "返回值: $?"  # 输出: 0

4.2 使用echo返回 #

bash
#!/bin/bash

# 返回字符串
get_full_name() {
    local first="$1"
    local last="$2"
    echo "$first $last"
}

name=$(get_full_name "张" "三")
echo "全名: $name"

# 返回计算结果
add() {
    local a=$1
    local b=$2
    echo $((a + b))
}

result=$(add 5 3)
echo "结果: $result"

# 返回数组
get_numbers() {
    echo "1 2 3 4 5"
}

numbers=($(get_numbers))
echo "数组: ${numbers[@]}"

4.3 返回多个值 #

bash
#!/bin/bash

# 方式一:使用全局变量
get_user_info() {
    user_name="张三"
    user_age=25
    user_city="北京"
}

get_user_info
echo "姓名: $user_name"
echo "年龄: $user_age"
echo "城市: $user_city"

# 方式二:使用echo返回多行
get_user_info2() {
    echo "张三"
    echo "25"
    echo "北京"
}

read -r name age city <<< "$(get_user_info2)"
echo "姓名: $name, 年龄: $age, 城市: $city"

# 方式三:使用关联数组
get_user_info3() {
    declare -A user
    user[name]="张三"
    user[age]=25
    user[city]="北京"
    
    # 返回键值对
    for key in "${!user[@]}"; do
        echo "$key=${user[$key]}"
    done
}

declare -A result
while IFS='=' read -r key value; do
    result[$key]="$value"
done < <(get_user_info3)

echo "姓名: ${result[name]}"

五、局部变量 #

5.1 使用local关键字 #

bash
#!/bin/bash

# 全局变量
global_var="全局变量"

test_scope() {
    # 局部变量
    local local_var="局部变量"
    
    echo "函数内 - 全局: $global_var"
    echo "函数内 - 局部: $local_var"
    
    # 修改全局变量
    global_var="修改后的全局变量"
}

test_scope

echo "函数外 - 全局: $global_var"
echo "函数外 - 局部: $local_var"  # 空值

5.2 变量作用域示例 #

bash
#!/bin/bash

count=0

increment() {
    local count=10
    ((count++))
    echo "函数内 count: $count"
}

increment        # 输出: 11
echo "函数外 count: $count"  # 输出: 0

# 使用全局变量
increment_global() {
    ((count++))
    echo "函数内 count: $count"
}

increment_global  # 输出: 1
echo "函数外 count: $count"  # 输出: 1

六、实战示例 #

6.1 日志函数 #

bash
#!/bin/bash

# 日志级别
LOG_LEVEL=0  # 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR

log() {
    local level="$1"
    shift
    local message="$*"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    local level_num
    case "$level" in
        DEBUG) level_num=0 ;;
        INFO)  level_num=1 ;;
        WARN)  level_num=2 ;;
        ERROR) level_num=3 ;;
        *)     level_num=1 ;;
    esac
    
    if [ $level_num -ge $LOG_LEVEL ]; then
        echo "[$timestamp] [$level] $message"
    fi
}

log DEBUG "调试信息"
log INFO "普通信息"
log WARN "警告信息"
log ERROR "错误信息"

6.2 文件处理函数 #

bash
#!/bin/bash

# 检查文件
check_file() {
    local file="$1"
    
    [[ -z "$file" ]] && { echo "错误: 文件名为空"; return 1; }
    [[ ! -e "$file" ]] && { echo "错误: 文件不存在"; return 1; }
    [[ ! -f "$file" ]] && { echo "错误: 不是普通文件"; return 1; }
    [[ ! -r "$file" ]] && { echo "错误: 文件不可读"; return 1; }
    
    return 0
}

# 读取文件内容
read_file() {
    local file="$1"
    
    check_file "$file" || return 1
    
    while IFS= read -r line; do
        echo "$line"
    done < "$file"
}

# 写入文件
write_file() {
    local file="$1"
    local content="$2"
    
    echo "$content" > "$file"
}

# 追加内容
append_file() {
    local file="$1"
    local content="$2"
    
    echo "$content" >> "$file"
}

6.3 数学计算函数 #

bash
#!/bin/bash

# 加法
add() {
    echo $(($1 + $2))
}

# 减法
subtract() {
    echo $(($1 - $2))
}

# 乘法
multiply() {
    echo $(($1 * $2))
}

# 除法
divide() {
    if (( $2 == 0 )); then
        echo "错误: 除数不能为0" >&2
        return 1
    fi
    echo $(($1 / $2))
}

# 计算器
calculate() {
    local a=$1
    local op=$2
    local b=$3
    
    case "$op" in
        +) add $a $b ;;
        -) subtract $a $b ;;
        \*) multiply $a $b ;;
        /) divide $a $b ;;
        *) echo "未知运算符: $op" ;;
    esac
}

result=$(calculate 10 + 5)
echo "结果: $result"

七、函数最佳实践 #

7.1 命名规范 #

bash
#!/bin/bash

# 推荐:使用小写字母和下划线
get_user_info() { ... }
calculate_total() { ... }
process_file() { ... }

# 不推荐:使用大写字母
GET_USER_INFO() { ... }

# 推荐:函数名描述功能
check_file_exists() { ... }
validate_input() { ... }
send_notification() { ... }

7.2 函数注释 #

bash
#!/bin/bash

# 函数:获取用户信息
# 参数:
#   $1 - 用户ID
# 返回:
#   用户信息字符串
# 示例:
#   get_user_info 123
get_user_info() {
    local user_id="$1"
    # 函数实现
}

# 使用here document写注释
: << 'EOF'
函数:计算总价
参数:
  $1 - 单价
  $2 - 数量
返回:总价
EOF
calculate_total() {
    local price="$1"
    local quantity="$2"
    echo $((price * quantity))
}

7.3 错误处理 #

bash
#!/bin/bash

# 使用set -e和返回值
process_data() {
    local file="$1"
    
    # 验证输入
    if [[ -z "$file" ]]; then
        echo "错误: 文件名为空" >&2
        return 1
    fi
    
    # 检查文件
    if [[ ! -f "$file" ]]; then
        echo "错误: 文件不存在: $file" >&2
        return 1
    fi
    
    # 处理文件
    if ! grep -q "pattern" "$file"; then
        echo "警告: 未找到匹配模式" >&2
        return 2
    fi
    
    return 0
}

# 调用并处理错误
if ! process_data "test.txt"; then
    echo "处理失败"
    exit 1
fi

八、总结 #

8.1 函数要点 #

要点 说明
定义 函数名()
调用 直接使用函数名
参数 使用$1, $2, $@, $#
返回值 return返回状态码,echo返回数据
局部变量 使用local关键字

8.2 下一步 #

你已经掌握了函数基础,接下来让我们学习 函数参数,深入了解参数传递!

最后更新:2026-03-27