shell脚本需兼顾可读性、安全性和可维护性:开头明确解释器与用途,变量函数命名规范并加引号引用,启用set -euo pipefail严格模式,逻辑拆分为函数,日志分级输出,配置外置,权限设为755,上线前用shellcheck检查。

写 Shell 脚本不是“能跑就行”,而是要让别人(包括三个月后的你自己)一眼看懂、放心修改、安全复用。规范不是束缚,是降低协作成本、减少线上事故的基础设施。
脚本开头必须明确解释器和意图
第一行必须是 #!/bin/bash 或更通用的 #!/usr/bin/env bash,避免因系统默认 shell 不同导致语法错误。紧接着用注释说明脚本用途、作者、创建时间、参数用法和依赖项。比如:
- 功能一句话讲清:“每日清理 /var/log 下 30 天前的压缩日志”
- 参数写清楚:“-d DIR 指定日志目录(必选),-k 保留最近 N 个文件(默认7)”
- 依赖标出来:“需安装 findutils 4.6+,不依赖外部 Python 或 Perl”
变量与函数要“看得见、管得住”
所有变量名用小写加下划线(log_dir),赋值时等号两侧不加空格(log_dir="/var/log"),引用时一律加双引号("$log_dir")。常量全大写并只读声明(readonly MAX_AGE_DAYS=30)。函数以动词开头(cleanup_old_logs),每个函数顶部写明作用、输入参数、返回含义,并优先使用 local 声明局部变量。
- 避免全局污染:函数里不要直接改 PATH 或 IFS,要用就先保存后恢复
- 数组遍历必须用 "${array[@]}",否则含空格的元素会断开
- 临时文件用 mktemp 创建,退出前用 trap 清理
结构清晰比技巧炫酷更重要
把逻辑拆成独立函数,主流程只留调用顺序。不用堆在 main 里写几十行 if-else。缩进统一用 4 个空格,每行不超过 80 字符,管道符 | 和逻辑运算符后换行并缩进一层。条件判断统一用 [[ ]],不混用 [ ] 或 test。
- 启用严格模式:set -euo pipefail,未定义变量、命令失败、管道任一环节出错都立即终止
- 错误处理不靠运气:关键命令后加 || die "无法连接数据库",die 函数统一输出错误并退出
- 日志分级输出:log_info、log_warn、log_error,不混用 echo
工程化从文件管理和权限开始
脚本命名用蛇形小写加 .sh 后缀(rotate_nginx_logs.sh),不带空格或大写字母。文件编码为 UTF-8,权限设为 755(chmod 755 rotate_nginx_logs.sh)。配置项尽量抽到外部文件或环境变量中,脚本本身只负责逻辑。
- 不同环境用不同配置:生产环境走 /etc/rotate.conf,开发环境走 ./config/dev.conf
- 版本控制别忽略:脚本进 Git,但敏感配置(如密码)不提交,用占位符 + 部署时注入
- 上线前跑一遍 shellcheck -s bash script.sh,自动发现常见陷阱











