以为玩透了crontab!直到定时任务偷偷罢工了一整周

举报
yd_222034595 发表于 2026/11/02 19:07:06 2026/11/02
【摘要】 crontab 里一个不起眼的 %,让我的备份日志静默消失了一整周。手动能跑、cron 不行,到底谁在捣鬼?

我一直觉得自己挺懂定时任务的。

不就是五个星号加一条命令嘛。分时日月周,写好时间,写好脚本,crontab -e 一粘,完事。能有多难?

直到那一周。

事情的起因

那个周一,我心血来潮检查了一下备份服务器,发现最近七天的备份日志……是空的。

不是报错,不是失败,是根本没有日志文件产生。

我心里咯噔一下,第一时间怀疑是不是整个备份流程都挂了。赶紧去翻实际备份出来的文件——还好,数据都在,每一天的备份包都规规矩矩躺在那里。

也就是说:备份成功了,但日志没生成。

这个诡异程度,大概就是"你打了人,人没叫"那种感觉。

一通乱查

我自信满满地开始排查。

备份脚本是这么个结构:先打包,再 echo 一行成功信息重定向到日志文件,日志文件名用日期拼出来:

手动跑一遍,日志生成得好好的。

那为什么 cron 跑就没日志?

我开始疯狂怀疑一切可能:

  • 是不是 cron 服务挂了?systemctl status crond,在跑,没问题。
  • 是不是权限问题?cron 是 root 跑的,/var/log 写得动,没问题。
  • 是不是 $() 在 cron 里不支持?换成反引号,还是没日志。
  • 是不是 PATH 问题导致 date 命令找不到?我特意在脚本里用 /bin/date 全路径调用,还是没日志。
  • 是不是 SELinux 拦了?查了一圈 audit 日志,没相关记录。
  • 是不是脚本根本没被 cron 执行?我在脚本开头加了个 touch /tmp/cron-ran,结果这个文件出现了。说明脚本确实跑了,备份也确实做了,就偏偏那条 echo 死活不产日志。

一整个下午,我在本机和备份服务器之间来回切换,脚本改了又改,重定向符号试了 > >> 2>&1 各种排列组合。没有。

五点半,我快要把锅甩给"这台机器中邪了"的时候,我做了一件事:我把 crontab 里那行原封不动复制出来,贴到终端里手动跑了一遍。

手动跑,日志生成。

盯着终端里那行命令看了大概十秒,我突然注意到一个细节——终端里一切正常,但 crontab 里有那么一个字符,在我的记忆里一直觉得它"无害"。

那个字符是:%。

真相

熟悉 cron 的人这时候大概要笑出声了。

crontab 里,% 是一个有特殊含义的字符——它被当作换行符。这是 cron 的一条古老规则:命令部分里,第一个 % 之后的内容会被当作标准输入喂给命令,% 本身被替换成换行。

于是我的 $(date +%Y%m%d),在 cron 眼里变成了这样:

(换行)

(换行)

date 拿到的参数变成了一坨跨好几行的乱码,要么报错,要么吐出一串谁都看不懂的东西。而那条 echo 的重定向,因为命令本身已经被换行符拆得稀碎,整个命令结构都变了——日志文件名根本没拼出来,重定向落空,那行 echo 静默地、优雅地、什么也没干。

备份的主体逻辑不依赖 %,所以照常成功;只有那条带 date +%... 的 echo,在 cron 里被无声地肢解了。

解决办法简单到令人窒息:在 % 前面加反斜杠转义,写成 \%。或者把日期拼接抽到脚本内部去执行,crontab 只负责调用脚本——脚本内部是不受 % 规则影响的。

我把日期拼接挪进了脚本里,保存,收工。从那以后日志再没缺过。

几条血泪教训

折腾一周换来的几句话,送给每一个"觉得自己懂 crontab"的人:

  1. crontab 里的 % 不是普通字符,它是换行符。 这一条坑过的人能从机房排到大门口。凡是 crontab 命令行里直接写 date +%Y%m%d 这种,百分号必须转义为 \%,否则就是一场静默的灾难。
  1. "手动能跑,cron 不行"几乎等于"环境差异问题"。 cron 的执行环境和你登录的 shell 完全是两个世界:PATH 极简、环境变量几乎没有、工作目录是 HOME。排查 cron 问题,第一步永远是"假设它在一个空荡荡的 shell 里跑",而不是"我手动跑过了所以没问题"。
  1. 静默失败是最阴险的失败。 备份能成、日志没成,这种"部分成功"比"整体崩溃"可怕得多——因为你会很长一段时间都以为一切正常。给关键任务加一个"执行后必须留下可见痕迹"的校验,比加一万行日志都有用。
  1. 能放进脚本里的逻辑,就别留在 crontab 里。 crontab 只负责"什么时候、调谁",具体命令越短越好。日期拼接、条件判断、复杂重定向,统统塞进脚本文件。crontab 里的命令越像"一句话",越不容易踩到 cron 那一堆藏在语法里的特殊规则。

最后

那一周之后,我对 crontab 的态度从"五个星号而已"变成了"五个星号,外加一堆埋在语法里的地雷"。

越是看起来人畜无害的工具,翻车时越没有现成文档可查——因为大家都觉得它"简单",没人专门写"我因为一个百分号排查了一周"这种事。

所以我写了。

希望你看完之后,下次往 crontab 里粘带 date 的命令,第一反应是"转义百分号了吗",而不是像我一样,从 SELinux 开始怀疑。那个 %,真的很重要。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。