脚本是用来解决问题的,但也很容易变成一堆难以维护的“一次性代码”。遵循一些简单规范,可以让脚本更容易被自己或他人理解、复用和排查。
1. 命名
- 文件名要有意义,反映功能:用
backup_db.sh而不是test1.sh。多个单词建议用下划线分隔,如deploy_staging.sh。 - 避免与系统命令重名:不要给脚本取
test、ls、cp这类名字,执行时可能会意外调用系统命令,也可能让其他用户困惑。 - 变量名小写,环境变量和常量大写:局部变量用小写加下划线(如
source_dir),全局或环境变量用大写(如BACKUP_DIR、DB_HOST),一眼就能区分作用域。 - 函数名采用动词+名词:如
check_disk_space()、send_alert(),表明功能。
2. 注释
- 在脚本顶部添加简要说明:至少包含脚本用途、用法、重要依赖,必要时加上作者和修改日期。
#!/bin/bash
# 用途:备份 MySQL 数据库并保留最近 7 份备份
# 用法:./backup_mysql.sh <database_name>
# 依赖:mysqldump, gzip
- 关键步骤前加注释:不是解释命令本身,而是解释“为什么要这样做”或“这个操作的前置条件”。
# 先获取当前时间戳,避免在循环中反复调用 date,提升效率
- 避免冗余注释:
i=0 # 将 i 赋值为 0这类纯粹翻译代码的注释是噪音。代码本身清晰的逻辑无需刻意注释。 - 用注释标记待办或风险点:
# TODO: 增加错误检查或# FIXME: SSH 连接超时可能导致卡死能帮助后续维护。
3. 缩进
- 统一使用空格:建议用 2 个或 4 个空格作为一级缩进,不要混用 Tab 和空格。许多编辑器能将 Tab 自动转换为空格,开启此选项。
- 保持结构对齐:
if、for、while的then、do与对应的关键词放在同一行,或采用易读的块风格。
if [[ -f "$file" ]]; then
echo "存在"
else
echo "不存在"
fi
- 长命令换行:在管道、逻辑运算符处断行,用反斜杠或自然的管道续行,缩进以显示连续关系。
find /data -type f -name "*.log" -mtime +30 \
-exec gzip {} \;
4. 错误处理
这是脚本可靠性的核心。放任错误会导致脚本在不确定状态下继续运行,可能造成更大破坏。
- 设置严格模式:脚本开头加上:
set -euo pipefail
set -e:任何命令返回非零(错误)立即退出,避免后续代码在异常状态下执行。set -u:使用未定义变量时报错退出,防止变量名拼写错误带来的隐蔽问题。set -o pipefail:管道中任一命令失败,整个管道返回失败,而不仅仅是最后一个命令的退出码。
- 显式处理可能失败的关键操作:即使开启了
set -e,也需要在特定场景下自行判断。
if ! mysqldump -u root mydb > "$backup_file"; then
echo "数据库备份失败" >&2
exit 1
fi
- 清理临时文件:用
trap确保无论脚本正常结束还是中途出错退出,都能执行清理。
tempfile=$(mktemp)
trap 'rm -f "$tempfile"' EXIT
- 退出码要有规范:主流程成功时
exit 0;不同错误情况使用不同非零码(1,2,...),注释说明含义,方便调用者判断。
遵守这些规范并不增加太多工作量,但能显著降低排查问题和合作维护时的痛苦。脚本是给人看的,顺便给机器执行,清晰的风格会让你的脚本从“能用”升级为“好用”。