一、为什么 cron 更容易出问题

定时任务最容易踩坑的地方在于:命令在交互式终端能成功,并不代表放到 cron 里也一定能成功。

原因通常包括:

  • 环境变量不完整
  • 相对路径失效
  • 输出没有重定向
  • 特殊字符在 cron 里有额外含义

所以,定时任务除了“能写出来”,更重要的是“能长期稳定运行”。

二、定时任务的几个关键习惯

2.1 给任务加注释

写定时任务时,建议尽量在上方加注释,说明任务用途。

这样做的好处是:

  • 以后自己回头看得懂
  • 团队协作时别人也能快速理解
  • 出问题时更容易定位任务作用

2.2 尽量用脚本承载业务逻辑

原始笔记非常强调:复杂逻辑不要直接堆在 crontab 里,而应尽量封装成脚本。

调试脚本时,可以使用:

$ sh -x backup-conf.sh

或者:

$ bash -x backup-conf.sh

这样可以直接看到脚本执行过程,排错效率会高很多。

2.3 文件和脚本尽量使用绝对路径

cron 环境下,相关文件最好写绝对路径,例如:

/server/scripts/backup-etc.sh

2.4 命令也尽量用绝对路径

如果在定时任务里直接写命令,也建议尽量写成绝对路径。

例如:

/sbin/ntpdate ntp1.aliyun.com

2.5 一定要处理输出

cron 执行时,如果命令或脚本有输出,又没有做重定向,系统通常会把输出通过邮件发给 root,或者在本地邮件目录不断堆积小文件。

常见写法:

# 重定向到空
*/2 * * * * /sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1

# 追加到日志文件
* * * * * echo oldboy >>/tmp/lidao.txt 2>&1

# 备份脚本调试日志
00 01 * * * /bin/sh -x /server/scripts/backup-etc.sh >>/tmp/script.log 2>&1

三、常见故障一:cron 里的 % 有特殊含义

在 cron 中,% 不是普通字符,往往会被当作换行或特殊分隔处理。

如果你在定时任务里直接写包含 % 的命令,比如 date +%F,就要特别小心,必要时需要做转义或改写到脚本里再执行。

最稳妥的方式通常是:

  • 把复杂命令写进脚本
  • 在脚本中使用 date +%F
  • crontab 只调用脚本

四、常见故障二:命令路径问题

4.1 典型现象

命令行里手工执行成功,但放进 cron 后提示命令找不到。

4.2 原因

cron 的运行环境通常只认识有限的 PATH,常见只包含 /bin/usr/bin 等基础路径。像 /sbin/ip 这类命令,如果不写绝对路径,cron 可能就找不到。

4.3 解决方法

方法一:直接写绝对路径

#!/bin/bash
hostname
/sbin/ip a s eth0

方法二:在脚本里重新定义 PATH

#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
hostname
ip a s eth0

方法三:重新加载系统环境

#!/bin/bash
source /etc/profile
hostname
ip a s eth0

五、常见故障三:没有重定向导致邮件堆积

5.1 典型现象

如果邮件服务开启,系统可能不断提示:

You have new mail in /var/spool/mail/root

如果邮件服务关闭,也可能在本地临时目录或邮件投递目录里不断积累小文件,例如:

/var/spool/postfix/maildrop

5.2 原因

cron 执行命令时只要有输出,就可能通过邮件形式发送给 root。

5.3 解决方法

把命令输出重定向到空设备或文件:

*/2 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null
* * * * * echo oldboy >>/tmp/lidao.txt 2>&1
00 01 * * * /bin/sh -x /server/scripts/backup-etc.sh &>>/tmp/scripts.log

六、小结

cron 最稳的写法,通常都符合这几个原则:

  • 有注释
  • 逻辑放脚本里
  • 路径尽量写绝对路径
  • 复杂环境变量自己显式处理
  • 所有输出都明确重定向

把这些习惯固定下来,定时任务的稳定性会明显提升,排障也会简单很多。