Shell 脚本编写的五个好习惯

举报
yd_211758112 发表于 2026/10/31 10:32:09 2026/10/31
【摘要】 Shell 脚本在自动化运维、CI/CD 和日常工具链中无处不在,但一个看似能跑的单文件脚本,往往在真实环境里暴露出各种隐患。与其靠踩坑补课,不如从写起就养成五个好习惯,让脚本更健壮、更易维护。 一、把 set -euo pipefail 放在脚本开头这是最便宜也最有效的一道防线。-e 让脚本在任意命令非零退出时立刻终止,而不是继续往下执行并在错误状态上层层掩盖;-u 对未定义的变量直接报错...

Shell 脚本在自动化运维、CI/CD 和日常工具链中无处不在,但一个看似能跑的单文件脚本,往往在真实环境里暴露出各种隐患。与其靠踩坑补课,不如从写起就养成五个好习惯,让脚本更健壮、更易维护。

一、把 set -euo pipefail 放在脚本开头

这是最便宜也最有效的一道防线。-e 让脚本在任意命令非零退出时立刻终止,而不是继续往下执行并在错误状态上层层掩盖;-u 对未定义的变量直接报错,避免把空值当成合法输入传给后续命令;-o pipefail 让管道的退出码反映整条管道里第一个非零退出(默认只看最后一段),这样 grep 找不到匹配、awk 解析失败都不会被后面的 echo / cat 吞掉。建议把它写成一行,紧跟 shebang 之后:

#!/usr/bin/env bash
set -euo pipefail

如果遇到某段命令允许失败(比如尝试性清理),可以显式用 || true 或 if 分支承接,而不是全局关掉 -e,这样读脚本的人一眼就知道哪里是刻意放行。

二、变量永远加双引号

未经引号保护的 $var 遇到空格、通配符或空值,都会在词法分析阶段产生意料之外的行为。"$var" 保证变量按一个词展开;当变量为空时,"" 保留为一个空参数而不是被删除,这对 rm -f "$dir" 之类的命令尤为关键。例外是显式做 glob 展开(如 *.log)或在 for 循环的 unquoted 遍历时不加引号,但这类场景应加注释说明意图。对数组和命令替换同样适用:用 printf '%s\n' "$(cmd)" 而不是直接 echo $(cmd),避免 echo 吞掉 -n / -e 或受空参数影响。

三、用函数组织逻辑,而不是在顶层写一长串

超过三四十行的脚本就该考虑拆分了。把"准备环境 / 拉取数据 / 转换 / 输出 / 清理"拆成同名函数,主流程变成一份可读的执行清单。函数内部优先使用局部变量(local var=…),避免污染全局;需要跨函数共享的状态尽量通过参数和返回值传递,而不是依赖隐式的全局变量。遇到复杂的分支,让函数只做一件事并返回退出码,调用方根据退出码决定重试、降级还是中止,后续加上日志后也更容易定位是哪一层出了问题。

四、重视日志与退出码

生产脚本最怕"静默失败"。与其满屏 echo,不如写一个 log 函数,统一带上时间戳和级别,输出到 stderr,方便和标准输出分离:

log_info()  { echo "[INFO]  $(date '+%Y-%m-%dT%H:%M:%S%z') $*" >&2; }
log_error() { echo "[ERROR] $(date '+%Y-%m-%dT%H:%M:%S%z') $*" >&2; }

配合 set -e 时,最后一条执行的语句的退出码就是脚本的退出码,因此在函数末尾不要把重要检查藏在管道里,也不要无差别 echo "done" 覆盖真实错误。对外暴露的脚本应在文档或 help 分支中写清每个非零退出码的含义(例如 1 参数错误、2 环境缺失、3 运行失败),方便上层 CI 或调用脚本做判断。

五、在提交前用 shellcheck 跑一遍

shellcheck 几乎能覆盖上面四条的常见疏忽:它会提醒你 set 选项缺失、变量未加引号、$(…) 内的换行风险、被命令替换吞掉的返回值,以及 grep | while 造成的子 shell 作用域丢失等。在本地直接 shellcheck script.sh,或把它挂到 pre-commit / CI 阶段,让检查变成流程而不是记忆。遇到 shellcheck 报告但确有理由的场景,用 # shellcheck disable=SCxxx 在行内关闭并附原因注释,而不是全局关掉。记住:shellcheck 报告的是"可能出问题的写法",最终是否修正仍取决于你对执行环境的判断,但它能把大量低级错误拦截在运行之前。

小结

五个习惯并不冲突,反而互相放大效果:set -euo pipefail 让错误尽早暴露,引号让变量行为可预测,函数让结构清晰,日志与退出码让故障可追踪,shellcheck 在前置环节兜底。坚持下来,脚本从"能跑"进化到"敢在生产跑",维护成本会显著下降。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。