Shell脚本如何实现函数库调用

wen 实用脚本 1

Shell脚本函数库调用的最佳实践:从封装到模块化

📚 目录导读

  1. 函数库的核心价值与设计原则
  2. 创建可复用的Shell函数库文件
  3. 函数库的调用方式详解
  4. 实战:构建一个日志与系统检测函数库
  5. 常见问题与性能优化技巧

函数库的核心价值与设计原则

Q:为什么Shell脚本需要函数库?
A:当脚本超过50行时,重复代码会导致维护噩梦,函数库通过封装通用逻辑(如日志记录、文件检测、错误处理)实现“一次编写,多处调用”,显著提升复用性。

Shell脚本如何实现函数库调用

设计三原则

  • 单一职责:每个函数只做一件事(如check_disk()只检测磁盘)
  • 命名规范:使用lib_前缀避免冲突(如lib_log_info
  • 无副作用:函数内部不使用exit,仅返回状态码或输出

创建可复用的Shell函数库文件

1 标准函数库结构示例

#!/bin/bash
# filename: mylib.sh
# 日志函数,用法:log_info "消息"
function lib_log_info() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1"
}
# 错误处理函数
function lib_assert_fail() {
    lib_log_info "错误:$1"
    return 1
}
# 文件存在性检测
function lib_file_exists() {
    [ -f "$1" ] && return 0 || return 1
}

2 函数库的关键要素

  • 避免全局变量污染:所有变量使用local声明
  • 提供帮助注释:每个函数顶部写明用法

函数库的调用方式详解

1 方法一:source命令(推荐)

原理:将函数库载入当前Shell环境
语法source /path/to/mylib.sh 或简写为 . /path/to/mylib.sh

示例

#!/bin/bash
source ./mylib.sh  # 加载库
lib_log_info "脚本开始"
if lib_file_exists "/etc/passwd"; then
    lib_log_info "密码文件存在"
fi

优点:函数直接调用,无路径限制
缺点:污染当前命名空间(通过脚本退出自动清除)

2 方法二:绝对路径调用

适用:库文件与主脚本在不同目录
示例

BASE_DIR=$(dirname "$0")
. "${BASE_DIR}/libs/mylib.sh"   # 通过脚本所在目录定位

3 方法三:通过函数返回结果

# 库函数返回数值
function lib_get_http_code() {
    curl -s -o /dev/null -w "%{http_code}" "$1"
}
# 调用方获取结果
HTTP_CODE=$(lib_get_http_code "https://tools.fan")
echo "HTTP状态码:$HTTP_CODE"

实战:构建一个日志与系统检测函数库

1 创建 sys_lib.sh(部分代码)

# 系统检测函数集 (仅示例核心部分)
# 检测磁盘使用率
function check_disk_usage() {
    local mount_point=${1:-"/"}
    local threshold=${2:-80}  # 默认80%
    local usage=$(df "$mount_point" | tail -1 | awk '{print $5}' | sed 's/%//')
    [ "$usage" -ge "$threshold" ] && return 1 || return 0
}
# 检测进程是否运行
function check_process() {
    local proc_name=$1
    pgrep -x "$proc_name" > /dev/null 2>&1 && return 0 || return 1
}

2 主脚本调用示例(monitor.sh

#!/bin/bash
source ./sys_lib.sh
source ./mylib.sh
lib_log_info "开始系统检测"
if check_disk_usage "/" 85; then
    lib_log_info "磁盘正常"
else
    lib_log_info "磁盘告警"
fi
if check_process "nginx"; then
    lib_log_info "nginx运行中"
fi

3 执行输出

[2025-04-07 10:30:15] [INFO] 开始系统检测
[2025-04-07 10:30:15] [INFO] 磁盘正常
[2025-04-07 10:30:15] [INFO] nginx运行中

常见问题与性能优化技巧

Q1:函数库无法找到函数怎么办?

排查

  1. 确认source路径正确(使用realpath生成绝对路径)
  2. 检查库文件是否有执行权限(chmod +x不影响source)
  3. 避免函数名与系统命令重名(如不要命名为test

Q2:函数库如何跨模块共享变量?

方案:通过函数返回值传递,而非全局变量

# 正确方式:将输出赋给变量
STATUS=$(check_disk_usage)  

Q3:大型函数库如何分割?

模块化

lib/
├── core_logger.sh
├── net_check.sh
├── system_info.sh
└── main_loader.sh  # 一次性加载所有

main_loader.sh

for lib in /opt/libs/*.sh; do
    [ -f "$lib" ] && source "$lib"
done

性能优化建议

  1. 延迟加载:只在需要时source函数库,避免启动时加载全部
  2. 使用函数缓存:对高频调用的函数(如文件检测)尽量使用eval避免fork子进程
  3. 避免在函数中使用grep/sed:改用内置参数替换${var##*/}

延伸思考:如果需要跨语言调用(如Python调用Shell库),可以将Shell函数封装为--help命令行接口,并通过bash -c "source lib.sh; my_func"执行,实现语言中立。

(全文完)

本文所有示例已在 Bash 4.4+ 环境测试通过,建议在 /root/scripts/libs/ 下统一管理函数库,并在主脚本中通过 BASE_DIR=$(dirname "$0") 实现路径自适应。

抱歉,评论功能暂时关闭!