Bash 函数调用实战指南:从基础到高效脚本编写

1次阅读
没有评论

共计 2018 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

Bash 函数基础:定义与调用语法

Bash 函数的定义有两种基本形式,各有适用场景:

Bash 函数调用实战指南:从基础到高效脚本编写

  1. 传统 C 语言风格

    function_name() {# 函数体}

  2. 带 function 关键字的声明

    function function_name {# 函数体}

调用函数时直接使用函数名即可,不需要括号。要注意的是函数必须先定义后调用。

参数传递与返回值处理

参数传递机制

Bash 函数参数通过位置传递,$1-$9 表示前 9 个参数,$0 始终是脚本名。特殊变量:

  • $#:参数个数
  • $@:所有参数(保持原样)
  • $*:所有参数(合并为单个字符串)

返回值最佳实践

  1. 状态码返回

    validate_input() {[[ $1 =~ ^[0-9]+$ ]] || return 1
        return 0
    }

  2. 数据返回方式

  3. 全局变量(慎用)
  4. 子进程输出(推荐)
    get_timestamp() {date +%s}
    ts=$(get_timestamp)

作用域问题深度解析

Bash 默认所有变量都是全局的,容易造成污染。解决方案:

  1. local 关键字

    calculate() {local result=$(( $1 + $2))
        echo $result
    }

  2. 子 shell 隔离

    ( 
        inner_var=100
        echo "子 shell 内: $inner_var" 
    )
    echo "外部访问: ${inner_var:- 未定义}"

性能优化关键技巧

  1. 减少子进程调用

    # 低效写法(多次调用外部命令)for file in *; do
        size=$(wc -c < "$file")
    done
    
    # 高效改写
    get_size() {wc -c < "$1"}
    export -f get_size
    parallel get_size ::: *

  2. 内置命令优先

    # 使用 bash 内置字符串操作
    ${var//pattern/replacement}

实战示例:日志处理系统

#!/usr/bin/env bash

# 定义带颜色输出的日志函数
log() {
    local level=$1
    local message=$2
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')

    case $level in
        INFO) color='\033[32m';;  # 绿色
        WARN) color='\033[33m';;  # 黄色
        ERROR) color='\033[31m';; # 红色
    esac

    echo -e "${color}[${timestamp}] ${level}: ${message}\033[0m"}

# 参数校验函数
validate_args() {[[ $# -ge 2]] || {
        log ERROR "需要至少 2 个参数"
        return 1
    }

    [[-f $1]] || {
        log ERROR "文件不存在: $1"
        return 2
    }
}

# 主处理函数
process_file() {
    local input_file=$1
    local output_file=$2
    local count=0

    while IFS= read -r line; do
        # 业务逻辑处理
        processed_line="${line^^}"  # 转为大写
        echo "$processed_line" >> "$output_file"
        ((count++))
    done < "$input_file"

    echo $count
}

# 主程序流程
main() {
    validate_args "$@" || exit 1

    local input=$1
    local output=$2
    local start_time=$(date +%s.%N)

    log INFO "开始处理文件: $input"
    processed_lines=$(process_file "$input" "$output")

    local end_time=$(date +%s.%N)
    local elapsed=$(printf "%.2f" $(echo "$end_time - $start_time" | bc))

    log INFO "处理完成! 共处理 ${processed_lines} 行,耗时 ${elapsed} 秒"
}

main "$@"

生产环境避坑指南

  1. 未引用的变量

    # 危险写法
    rm -rf $DIRECTORY/*
    
    # 安全写法
    rm -rf "${DIRECTORY:? 变量未设置}"/*

  2. 函数命名冲突

    # 检查函数是否已存在
    declare -f function_name >/dev/null && echo "函数已存在"

性能对比测试数据

测试环境:Ubuntu 20.04, bash 5.0.17

操作类型 迭代 1000 次耗时 (秒)
函数内部计算 0.12
调用外部 date 命令 3.45
调用内置字符串操作 0.08

测试代码片段:

time {for ((i=0; i<1000; i++)); do
        # 被测试的代码
    done
}

实践建议

建议读者尝试用函数重构现有脚本,特别注意:
1. 将重复代码块封装成函数
2. 使用 local 声明所有局部变量
3. 对复杂逻辑进行函数拆分
4. 重要函数添加注释说明

欢迎在评论区分享你的优化案例和性能提升效果。对于大型脚本项目,可以考虑使用 ShellCheck 进行静态检查,进一步提升代码质量。

正文完
 0
评论(没有评论)