Crontab 是 Linux 上最经典的定时任务调度工具,从定时备份、日志清理、证书续签到定期同步数据,都可以用它实现全自动执行。本文讲清 crontab 的语法规则、编辑方法、日志记录、常见示例,以及容易踩坑的时区与环境变量问题。

本文要点

  • crontab 时间字段语法速查(五字段含义)
  • 用 crontab -e 编辑,用 -l 查看,用 -r 删除
  • 输出重定向到日志文件,便于排查
  • PATH 与环境变量陷阱
  • 时区设置(系统时区 vs CRON_TZ)

crontab 时间语法

每条 crontab 任务由 5 个时间字段和命令组成:

# ┌───────────── 分钟(0–59)
# │ ┌─────────── 小时(0–23)
# │ │ ┌───────── 日(1–31)
# │ │ │ ┌─────── 月(1–12)
# │ │ │ │ ┌───── 星期(0–7,0 和 7 都是周日)
# │ │ │ │ │
  * * * * *  要执行的命令
特殊字符含义示例
*任意值* 表示每分钟/每小时/每天
,枚举1,15 表示 1 日和 15 日
-范围1-5 表示周一到周五
/步长*/5 表示每 5 个单位
@reboot开机执行@reboot 命令

常用时间表达式速查

表达式含义
0 3 * * *每天凌晨 3 点
*/10 * * * *每 10 分钟一次
0 0 * * 0每周日午夜
0 0 1 * *每月 1 日午夜
0 8-18 * * 1-5工作日 8:00–18:00 每整点
@reboot系统启动后执行一次

编辑与管理 crontab

# 编辑当前用户的 crontab(使用系统默认编辑器)
crontab -e

# 查看当前 crontab 内容
crontab -l

# 编辑指定用户的 crontab(root 操作)
crontab -u www-data -e

# 删除当前用户全部 crontab(危险!)
crontab -r

crontab -r 无确认提示

执行 crontab -r 会立即删除当前用户的全部定时任务且不会弹出确认提示。建议先用 crontab -l > crontab.bak 备份,再执行删除。

将输出重定向到日志

默认情况下 crontab 的输出会通过 sendmail 发送给用户,通常收不到。应将输出显式重定向到日志文件:

# 将标准输出和错误都写到日志
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# 带时间戳的日志写法
0 3 * * * echo "[$(date)] start" >> /var/log/myjob.log; /usr/local/bin/myjob.sh >> /var/log/myjob.log 2>&1

# 如果不想要任何输出(静默执行)
0 3 * * * /usr/local/bin/myjob.sh > /dev/null 2>&1

PATH 与环境变量问题

crontab 运行时的 PATH 比交互式 Shell 短得多,很多命令找不到。有两种解决方法:

# 方法一:在 crontab 文件顶部设置 PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 方法二:在脚本或命令中使用绝对路径
0 3 * * * /usr/local/bin/rclone copy /backup r2:bucket/ >> /var/log/upload.log 2>&1

时区设置

crontab 默认使用系统时区,搬瓦工 VPS 出厂通常为 UTC。先确认:

# 查看当前系统时区
timedatectl

# 修改系统时区为北京时间
timedatectl set-timezone Asia/Shanghai

# 或只为当前 crontab 指定时区(在 crontab 文件顶部)
CRON_TZ=Asia/Shanghai
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

时区与执行时间

UTC 时区下写 0 3 * * * 等于北京时间 11 点执行。如果你想让任务在北京时间凌晨 3 点运行,要么修改系统时区,要么加 CRON_TZ=Asia/Shanghai,要么把时间改成 19 0 * * *(UTC 19:00 = 北京 03:00)。

实用示例

# 每天凌晨 3 点运行备份脚本
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# 每周日凌晨 4 点清理 7 天以上的日志文件
0 4 * * 0 find /var/log/myapp -name "*.log" -mtime +7 -delete

# 每 5 分钟检查一次服务是否在运行,不在则重启
*/5 * * * * systemctl is-active --quiet nginx || systemctl restart nginx

# 每月 1 日续签 SSL 证书(Let's Encrypt)
0 2 1 * * certbot renew --quiet >> /var/log/certbot.log 2>&1

# 系统启动后立即同步时间
@reboot ntpdate -u pool.ntp.org

小结

  • 五字段语法:分 时 日 月 周,* 代表任意,/ 代表步长
  • crontab -e 编辑,-l 查看,备份后再 -r 删除
  • 所有任务输出重定向到日志,方便排查执行情况
  • 在 crontab 文件顶部设置 PATH 和 CRON_TZ 解决两大常见坑
  • 用 systemctl 结合 crontab 实现简单的进程守护

常见问题

crontab 任务没有按时执行,怎么排查?

先用 systemctl status cron(或 crond)确认 cron 服务在运行;再检查日志 /var/log/syslog 或 /var/log/cron 里有无错误信息;确认命令使用绝对路径;手动执行脚本看是否报错。

crontab 和 systemd timer 该用哪个?

crontab 更简单直接,适合大多数定时脚本场景。systemd timer 功能更强(支持依赖、错误处理、journald 日志),适合对可靠性要求更高的生产任务。

如何让脚本在每次 reboot 后自动启动?

在 crontab 中加一行 @reboot /路径/脚本.sh 即可。如果需要更健壮的自启,推荐用 systemd service 配置 WantedBy=multi-user.target。

定时任务能操作数据库吗?

可以。脚本中直接用 mysql -u user -ppassword dbname -e 'SQL' 或 mysqldump 等命令即可。密码直接写在脚本里时注意文件权限,chmod 700 保证只有 owner 可读。