crontab定时任务配置

文章导读
搜「crontab定时任务配置」的人,多数不是想学 cron 语法,而是脚本在终端里能跑,挂到 crontab 后不执行、或者执行了但结果不对。先别改脚本逻辑,按顺序核对三件事:任务挂在哪一个用户的 crontab 下、cron 实际用的 PATH 和 shell 是什么、命令输出和报错被写到了哪里。这三项能对上,再谈时间表达式。
📋 目录
  1. 一 crontab定时任务:先把能核对的事实摆清楚
  2. 二 crontab定时任务最容易搞错的一点
  3. 三 crontab定时任务:一个照着就能做完的做法
  4. 四 crontab定时任务:怎么验证结果对不对
A A

搜「crontab定时任务配置」的人,多数不是想学 cron 语法,而是脚本在终端里能跑,挂到 crontab 后不执行、或者执行了但结果不对。先别改脚本逻辑,按顺序核对三件事:任务挂在哪一个用户的 crontab 下、cron 实际用的 PATH 和 shell 是什么、命令输出和报错被写到了哪里。这三项能对上,再谈时间表达式。

处理 crontab 不生效,建议按“用户身份 → 环境变量 → 输出与退出码”的顺序排查,而不是反复改时间表达式。先用 crontab -l 确认任务挂在哪个用户下,再把命令改成带绝对路径、重定向日志的写法,最后用 grep CRON /var/log/syslog 或 journalctl -u cron 看 cron 是否真的触发过。命令在终端能跑不代表在 cron 环境里能跑,PATH 和 shell 是两套环境;日志路径和 cron 服务名在不同发行版上可能不同,需要结合系统确认。

crontab定时任务:先把能核对的事实摆清楚

先只做记录,不下判断。需要核对的对象有四项:当前登录用户、该用户已有的 crontab 内容、cron 守护进程是否在运行、系统日志里 cron 的落点。

whoami
crontab -l
systemctl status cron 2>/dev/null || systemctl status crond 2>/dev/null
ls /var/log/cron /var/log/syslog 2>/dev/null

几条命令的含义:whoami 确认你此刻是哪个用户,因为 crontab -e 默认编辑当前用户的表,root 用户的表和普通用户的表互不可见;crontab -l 列出该用户已有的条目,如果提示 no crontab for xxx,说明这个用户下压根没有任务,而不是任务失效。systemctl status 用来区分 Debian/Ubuntu 系常见的 cron 与 RHEL/CentOS 系常见的 crond,服务名写错会得到误导性的“未运行”。

日志位置同样要实地确认:Debian/Ubuntu 通常把 cron 记录写进 /var/log/syslog,RHEL 系多在 /var/log/cron,使用 systemd 的系统也可以直接查 journalctl -u cron。具体以本机 ls 的结果为准,不要照搬别人博客里的路径。

另外要确认执行对象:任务里调用的脚本是哪个绝对路径、解释器是什么、脚本里有没有依赖登录 shell 才有的环境变量。这些都是能直接打开文件看到的,不需要猜测。

crontab定时任务最容易搞错的一点

最常见的误解是:把「命令在交互式终端里能跑通」当成「crontab 里也能跑通」。cron 启动任务时不会加载你的 ~/.bashrc、~/.bash_profile,PATH 通常很短,工作目录一般是执行用户的家目录,shell 也不一定是你登录时用的那个。所以 python xxx.py、node xxx.js、相对路径的 ./run.sh 都可能直接失败,而失败信息被 cron 默默吞掉。

判断分界很简单:如果任务在终端能跑、在 cron 里完全没动静,基本可以归到环境差异这一侧;如果 cron 日志里能看到任务被触发、但脚本内部逻辑报错,那属于脚本自身问题,跟 cron 配置关系不大。

crontab定时任务配置

一个能把两种情况区分开的检查动作:把原命令临时替换成一条只写环境信息的任务,等触发后看输出。

# 临时加一条,观察 cron 的真实环境
* * * * * /usr/bin/env > /tmp/cron_env_$(date +\%H\%M).log 2>&1

注意 crontab 里 % 有特殊含义,需要写成 \%。等一两分钟后查看 /tmp/cron_env_*.log:如果文件生成了,说明 cron 本身在工作、任务确实被触发,问题在命令环境;如果文件一直不生成,问题在调度层(服务没运行、时间表达式写错、任务挂在了别的用户下)。这条临时任务验证完就删掉。

crontab定时任务:一个照着就能做完的做法

下面是一条可以直接套用的路径,每一步都写明该看到什么。

第一步,确定任务的执行用户。如果需要 root 身份运行,用 sudo crontab -e -u root;如果要用某个普通用户,先 sudo -iu deploy 切过去再执行 crontab -e。编辑保存后立刻用 crontab -l -u 相应用户 回看,应该能看到刚写入的条目。

第二步,把命令改造成 cron 友好的形式:绝对路径、显式解释器、重定向输出。

# 备份示例:每天 02:30 执行,日志按天落盘
30 2 * * * cd /opt/app && /usr/bin/python3 /opt/app/backup.py >> /var/log/app_backup.log 2>&1

字段说明:30 2 * * * 依次是分、时、日、月、周;cd /opt/app && 用来固定工作目录,脚本里用到相对路径时不至于找不到文件;>> ... 2>&1 把标准输出和标准错误一起追加到日志,这是排查时唯一能依赖的东西。如果脚本依赖特定环境变量,可以在 crontab 顶部单独写一行,或在命令前用 env 拼接,例如 /usr/bin/env LANG=zh_CN.UTF-8 /usr/bin/python3 ...。

crontab定时任务配置

第三步,按验证节奏设置。调试阶段建议先用 */2 * * * * 这类短间隔跑一次,确认能正常产出后再改成目标时间。crontab 保存后不需要重启 cron 服务,编辑器退出即生效;但如果任务完全没有反应,可以 sudo systemctl restart cron 后观察,这一步只是排除,不是常规操作。

这一步该看到的结果是:crontab -l 回显包含新增条目、目标时间点过后日志文件出现新的追加内容。如果日志文件为空但确实被创建,说明命令执行了但没输出,需要回到脚本内部查。

crontab定时任务:怎么验证结果对不对

验证分两层:调度层确认 cron 触发过,执行层确认命令跑出了预期结果。

# Debian/Ubuntu
grep CRON /var/log/syslog | tail -n 20
# RHEL/CentOS
tail -n 20 /var/log/cron
# 使用 systemd 的系统
journalctl -u cron --since "-30 min"

正常结果长这样:日志里出现一条带时间戳的记录,包含 CMD 关键字和你写的完整命令。能看到这条,说明调度层没有问题,剩下只查脚本;看不到这条,说明 cron 没触发,回到用户身份和时间表达式上核对。

执行层的验证看三样:日志文件是否在预期时间后追加了新内容、脚本产出的文件或数据库记录是否按预期变化、任务的退出状态。对于需要关心成败的任务,可以在命令后追加判断,让失败留下痕迹:

30 2 * * * cd /opt/app && /usr/bin/python3 /opt/app/backup.py >> /var/log/app_backup.log 2>&1 || echo "backup failed at $(date)" >> /var/log/app_backup.err

判断标准建议写死:日志最后一段不含 Traceback、Permission denied、command not found 这类字样;产出文件大小非零;错误文件中没有新增行。任一条不满足,就按前面「先环境、后脚本」的顺序回头查,而不是继续微调时间表达式。需要提醒的是,时间表达式中的日和周同时限定时,不同实现的行为存在差异,若任务对日期敏感,建议只保留其中一个限制并在脚本里自行判断;具体可对照本机 man 5 crontab 的说明确认。