生产运维脚本禁用print(),须用logging分级记录;cron中需用绝对路径、显式设环境变量并校验用户;argparse应强制必填、禁用敏感默认值、提供--dry-run;异常处理要捕获具体类型、确保资源清理、规范退出码。

为什么 print() 不该出现在生产运维脚本里
运维脚本一旦进入线上环境,print() 会直接混入标准输出,干扰管道操作(比如 grep、awk 或日志采集器),也容易掩盖真实错误。更糟的是,它无法分级控制——你没法只让“警告”显示而屏蔽“调试信息”。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 统一用
logging模块,初始化时配置level和format,例如%(asctime)s %(levelname)s %(name)s %(message)s - 避免在模块顶层调用
logging.basicConfig(),改用显式Logger实例,方便被主程序接管日志配置 - 关键路径(如服务启停、文件备份)必须打
logging.info();异常分支必须打logging.error()并附带exc_info=True - 调试信息用
logging.debug(),上线前通过环境变量(如LOG_LEVEL=WARNING)关闭
如何让脚本在 cron 和手动执行时行为一致
cron 环境缺失用户 shell 配置(~/.bashrc)、PATH 不完整、HOME 可能为 /,导致依赖环境变量或相对路径的脚本静默失败。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 所有路径用绝对路径:
/opt/myapp/config.yaml而非./config.yaml或~/config.yaml - 显式设置必要环境变量:在脚本开头加
os.environ["PATH"] = "/usr/local/bin:/usr/bin:/bin" - 用
os.path.expanduser()处理用户家目录,但不要依赖~字符串字面量 - 检查当前用户权限:用
os.getuid()+pwd.getpwuid()校验是否为预期用户,避免 cron 以 root 运行却误写入普通用户目录
argparse 怎么设计才不反人类
运维人员常批量调用脚本,参数混乱或提示不清会导致重复执行失败、误删数据。别把 argparse 当成“有就行”,得让它扛住真实场景。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必填参数全用
required=True,别靠默认值蒙混——比如--host默认"localhost"在生产环境就是灾难 - 敏感参数(如
--password)禁用default,改用action="store_const"或从文件读取,且加help=argparse.SUPPRESS - 提供
--dry-run开关,所有变更操作前先打印将要执行的动作(如 “rm -f /data/old.log”),不真正执行 - 子命令比一堆互斥参数更清晰:用
subparsers拆出backup、restore、verify,每个子命令再定义自己专属参数
异常处理不是 try...except 套一层就完事
运维脚本崩溃不可怕,可怕的是崩溃后没留下线索、没清理临时状态、没通知负责人。裸抛异常或空 except: 是典型反模式。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 捕获具体异常类型:用
FileNotFoundError而非Exception,避免吞掉KeyboardInterrupt导致 Ctrl+C 失效 - 资源清理必须用
finally或contextlib.closing():打开的文件、临时目录、SSH 连接都要确保释放 - 对可恢复错误(如网络超时)做有限重试,用
time.sleep()加退避,别无限循环 - 致命错误(如磁盘满、权限拒绝)需调用
sys.exit(1)并在logging.critical()中包含上下文(当前工作目录、Python 版本、输入参数)
最常被忽略的一点:运维脚本的“退出码”本身就是接口。0 表示成功,非 0 表示不同失败类型(如 2=参数错误,3=连接失败),监控系统和上游流程全靠这个判断。别让 exit code 成为随机数。










