Linux 定时任务 cron 执行失败的常见原因

9次阅读

cron不加载shell配置导致命令找不到,需显式设PATH或用绝对路径;工作目录为根目录,须用cd切换;%等特殊字符需转义;应重定向日志并开启cron系统日志。

Linux 定时任务 cron 执行失败的常见原因

环境变量和 PATH 在 cron 中不生效

cron 启动时不会加载用户的 shell 配置(如 ~/.bashrc/etc/profile),所以脚本里用到的命令(比如 python3nodemysqldump)如果不在 /usr/bin/bin 下,就会报 command not found

解决方法:在 crontab 里显式设置 PATH,或用绝对路径调用命令:

PATH=/usr/local/bin:/usr/bin:/bin 0 2 * * * /usr/bin/python3 /home/user/backup.py

更稳妥的做法是,在脚本开头也手动补全环境,比如 Python 脚本里加:

import os os.environ['PATH'] = '/usr/local/bin:/usr/bin:/bin' + os.environ.get('PATH', '')
  • 别依赖 which python3 的输出来写 crontab —— 它在交互式 shell 里运行,和 cron 环境不一致
  • env > /tmp/cron_env.txt 临时 dump 出 cron 的真实环境,对比排查

cron 日志没开或看不懂错误输出

默认 cron 不会把执行失败的 stderr 打印到屏幕,也不会自动记录完整错误,只可能在系统日志里留一行“failed”。

务必让任务把输出重定向出来:

0 3 * * * /path/to/script.sh >> /var/log/myscript.log 2>&1

同时确认 rsyslogsyslog-ng 已启用 cron 日志:

  • 检查 /etc/rsyslog.conf 是否有 cron.* /var/log/cron 这行(取消注释)
  • 重启服务:sudo systemctl restart rsyslog
  • 然后用 sudo tail -f /var/log/cron 实时观察调度行为

注意:有些发行版(如 ubuntu 22.04+)默认禁用 cron 日志,需手动开启。

权限、路径、用户上下文不匹配

cron 以指定用户身份运行,但常被忽略的是:当前工作目录不是用户 home,也不是脚本所在目录,而是 / 根目录。所以脚本里所有相对路径(如 ./config.json../data/)都会失败。

  • 脚本开头强制切换工作目录:cd /home/user/myproject || exit 1
  • 用绝对路径读写文件,避免 open("log.txt") 这类调用
  • 确认目标用户对脚本、配置、输出目录都有读/写/执行权限(chmod +x 脚本,chown user:user /path/to/output
  • 如果是 root 用户的 crontab,而脚本里用了 sudo,大概率卡住或失败 —— cron 不支持交互式密码输入

特殊字符未转义导致语法解析失败

crontab 行里 % 是特殊字符,会被解释为换行并把后面内容当 stdin。如果你的命令含 date +%Y%m%decho "a%b",整行就直接被截断,cron 甚至不会尝试执行。

修复方式:对每个 % 加反斜杠转义:

0 4 * * * /usr/bin/bash -c 'echo "backup_$(date +%Y%m%d).tar.gz"' >> /tmp/backup.log

其他常见陷阱:

  • *? 在 shell 命令中要防止被 cron 提前展开(建议整个命令包在单引号里)
  • 脚本路径含空格?必须用引号包裹,但 crontab 对引号处理很脆弱,不如把路径软链到无空格位置
  • 编辑 crontab 一定要用 crontab -e,不要直接改 /var/spool/cron/* 文件 —— 权限或格式错一点,整个用户 crontab 就失效

真正难定位的问题,往往不是脚本逻辑错,而是 cron 本身在静默地跳过某一行 —— 检查 sudo grep CRON /var/log/syslog 输出里有没有 “Syntax Error” 或 “bad username” 这类提示,比反复试运行更高效。

text=ZqhQzanResources