这个场景要解决什么
脚本在终端里跑得好好的,放进 cron 就报命令找不到——九成是环境差异。cron 用的是极简环境:命令搜索路径通常只有系统基本目录,它不读用户的 shell 配置,也不加载别名。定位方法很直接:先把 cron 的真实环境打出来看,再决定是声明搜索路径、写绝对路径,还是加载专用环境文件。
基本信息
| 适用场景 | 任务手动能跑,cron 里报命令找不到 |
|---|---|
| 根本原因 | cron 的命令搜索路径极简,且不执行登录时的 shell 配置 |
| 三种修复 | 任务表顶部声明搜索路径、命令写绝对路径、脚本内加载专用环境文件 |
| 排查方式 | 临时任务把环境变量导出到文件,再与交互环境比对 |
典型使用场景
- 脚本调用了非系统目录里的工具,例如自定义安装的运行时
- 用到 java、node 这类存在多版本切换的运行环境
- 脚本里调用了定义在 shell 配置里的函数或别名
- 依赖特定的区域或字符集环境变量才能正确输出
- 迁移到新机器后才出现,说明目标机的安装路径不同
复现与定位
复现与定位
# 临时加一条,把 cron 的真实环境导出(用完立刻删除)
* * * * * env > /tmp/cron-env.txt
cat /tmp/cron-env.txt
# 在守护日志里确认报错内容
journalctl -u crond -n 20 --no-pager | tail
grep CRON /var/log/syslog | tail -n 10三种修复
三种修复
# ① 任务表顶部声明搜索路径
PATH=/usr/local/bin:/usr/bin:/bin
# ② 任务里直接写绝对路径
0 2 * * * /usr/bin/python3 /opt/app/job.py
# ③ 脚本内部加载专用环境文件
. /etc/app/env.sh
/opt/app/run.sh环境差异对照
| 项 | 交互登录 shell | cron |
|---|---|---|
| 命令搜索路径 | 包含用户自定义目录 | 通常只有系统基本目录 |
| 默认解释器 | 用户设置的登录 shell | 通常是精简的 /bin/sh |
| 别名与函数 | 已加载 | 完全不加载 |
| 工作目录 | 用户家目录 | 用户家目录,但相对路径不可依赖 |
| 任务输出 | 直接显示在终端 | 以邮件形式尝试投递,常被丢弃 |
核对命令真实位置要用 which -a 一次列出所有匹配;多版本环境里同一个命令名可能指向不同版本,只看一个结果会误判。
想加载登录环境时不要直接加载系统 profile:非交互环境下脚本可能中途退出,导致后面的命令整段不执行,改用专用环境文件更稳。