函数库文件需只定义函数、不执行命令,通过加载守卫、local变量、小写下划线命名及显式初始化确保安全复用。

把公用函数抽离到独立文件并在多个脚本中复用,核心就两点:用 source 加载,靠 规范写法 避免冲突和污染。
函数库文件怎么写才安全可靠
独立函数文件(比如 lib_common.sh)不是随便堆函数,得遵守几个硬性习惯:
- 只写函数定义,不执行任何命令(比如不直接调用
log_info "start",也不读取用户输入) - 函数名全小写+下划线,如
is_dir_empty、parse_config_line,避免和ls、echo等系统命令重名 - 加加载守卫,防止重复 source 导致函数重定义:
[[ ${LIB_COMMON_SH_LOADED} ]] && return; LIB_COMMON_SH_LOADED=1 - 所有临时变量都用
local声明,比如local tmp_file=$(mktemp),否则不同函数用同名变量(如i、ret)会互相覆盖 - 不依赖未声明的全局变量;如果需要配置项(如日志路径),要么通过参数传入,要么提供单独的
init_logging()函数由主脚本显式调用
主脚本里怎么正确引入和使用
加载必须放在脚本开头,且路径要写清楚:
- 同目录:用
source ./lib_common.sh - 子目录:用
source ./lib/network.sh - 统一安装路径(如
/opt/myapp/lib/):用绝对路径source /opt/myapp/lib/log.sh - 想走
PATH查找(类似which):可用source "$(command -v mylib.sh 2>/dev/null)",前提是已把库路径加入PATH
加载完成后,函数就和本地定义的一样,直接调用即可,比如 is_file_readable "/etc/passwd" 或 result=$(get_timestamp)。
跨文件传参和结果传递的实际做法
Shell 没有“返回值对象”,函数间传数据靠两种方式,选哪种看场景:
-
命令替换捕获输出:函数用
echo输出结果,主脚本用$(func_name arg1 arg2)拿回字符串。适合返回路径、ID、状态文本等,例如:conf_path=$(find_config_file "db") -
全局变量中转:适用于多个函数协同处理同一组数据(比如
parse_ini解析后把键值存进INI_SECTIONS数组,后续get_ini_value直接查)。注意变量名加前缀防冲突,如MYAPP_TMP_DIR
别用 return 传业务数据——它只能返回 0–255 的整数,且 $? 一被下条命令覆盖就丢了。
大型项目里的路径与维护建议
脚本多了容易乱,建议固定结构:
- 建
lib/目录放所有函数库,按功能分文件:lib/io.sh、lib/net.sh、lib/str.sh - 主脚本用相对路径加载,如
source "$(dirname "$0")/lib/io.sh",这样无论从哪启动都能定位 - 每个库文件顶部加简短注释说明用途和依赖,比如
# 提供文件锁、临时目录管理、原子写入等IO工具 - 上线前用
shellcheck扫描所有.sh文件,重点检查未声明变量、未引号包裹的参数、local缺失等问题











