macOS下cron定时任务运行Python脚本无法读取环境变量报错
问题根因
这不是权限问题,核心原因是cron定时任务的运行环境和你手动在终端/编辑器启动脚本的环境完全隔离:
- macOS下cron执行任务时只会加载系统级的极简默认环境,默认运行shell为
/bin/sh,不会主动加载zsh的用户级配置文件~/.zshenv - 你手动运行脚本时处于交互式zsh会话中,zsh会自动加载
~/.zshenv内的配置,因此可以正常读取SMTP凭据;cron环境中不存在对应环境变量,os.getenv()读取到的返回值就是None,传入smtp.login()后尝试调用encode()方法就会触发你看到的AttributeError报错。
解决方案
以下三种方案任选其一即可,优先推荐前两种配置成本更低的方案:
方案1:直接在crontab中声明环境变量(最稳定,不受shell配置影响)
- 终端执行
crontab -e打开当前用户的定时任务配置 - 在你的定时任务行上方直接添加需要的环境变量配置,示例:
EMAIL_ADDRESS="你的Gmail邮箱地址" EMAIL_PASSWORD="你的Gmail SMTP专用密码" # 原定时任务,注意写全python3和脚本的绝对路径 */30 * * * * /usr/bin/python3 /Users/ourcore/Documents/Dev/site_monitor/monitor.py
注意:Gmail SMTP登录需要使用开启两步验证后生成的应用专用密码,不能使用账号原登录密码。
- 终端执行
方案2:任务执行前主动加载zsh配置
不需要额外迁移环境变量,直接修改cron任务的执行命令,指定通过zsh启动执行流,先加载~/.zshenv配置再运行脚本,和你手动在终端运行的环境完全一致,示例:*/30 * * * * zsh -c 'source ~/.zshenv && /usr/bin/python3 /Users/ourcore/Documents/Dev/site_monitor/monitor.py'方案3:Python脚本内主动读取
~/.zshenv配置
如果不想修改crontab规则,可以在脚本读取环境变量的逻辑前,加一段主动解析~/.zshenv文件注入环境变量的代码,不依赖shell的配置加载逻辑,示例代码:import os from pathlib import Path # 主动加载~/.zshenv中的环境变量 zshenv_file = Path.home() / ".zshenv" if zshenv_file.is_file(): with open(zshenv_file, "r", encoding="utf-8") as f: for raw_line in f: line = raw_line.strip() if not line.startswith("export "): continue # 解析export开头的配置行 key, val = line[len("export "):].split("=", 1) # 去除值两侧的引号 val = val.strip("\'\"") os.environ[key.strip()] = val # 后续原有读取变量的逻辑不需要修改 EMAIL_ADDRESS = os.getenv("EMAIL_ADDRESS") EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD")
内容的提问来源于stack exchange,提问作者Mario Parra
相关产品推荐
相关产品推荐

