《Linux 定时任务 crontab 入门:语法、示例与常见坑》

举报
yd_286077367 发表于 2026/11/11 10:52:34 2026/11/11
【摘要】 一文讲清 Linux crontab 定时任务的语法、常用命令、真实示例,以及 PATH 不继承、% 转义、邮件丢失、任务重叠、日与周「或」逻辑等常见坑。

一、什么是 crontab

在 Linux 里,如果你希望某个命令或脚本按固定时间自动运行——比如每天凌晨备份数据库、每 5 分钟检查服务状态、每月 1 号清理日志——就不需要人工盯着终端一条条敲。crontab(cron table)就是 Linux 最常用的定时任务工具。

cron 守护进程(crond)会读取每个用户的定时任务表,在到达指定时间时自动执行对应的命令。你可以把它理解为「给 Linux 设闹钟」:时间一到,命令就跑。

1.1 相关文件

  • /etc/crontab:系统级 crontab,通常由 root 维护。
  • /etc/cron.d/ 目录:存放按文件拆分的系统定时任务。
  • /var/spool/cron/ 或 /var/spool/cron/crontabs/:存放每个用户的 crontab 文件(不要直接编辑,要用 crontab -e)。

日常使用中,普通用户基本只需要操作 crontab -e / crontab -l / crontab -r 三个命令。

二、crontab 基本语法

crontab 的核心只有一行一行的规则,每行代表一条定时任务。格式如下:

* * * * * command_to_execute
│ │ │ │ │
│ │ │ │ └── 星期(0-7,0 和 7 都表示周日)
│ │ │ └──── 月份(1-12)
│ │ └────── 日期(1-31)
│ └──────── 小时(0-23)
└────────── 分钟(0-59)

五个星号从左到右依次表示分、时、日、月、周,后面紧跟要执行的命令。

  • * 表示「任意 / 不限制」。
  • , 表示枚举,如 1,15 表示第 1 和第 15。
  • - 表示范围,如 1-5 表示 1 到 5。
  • / 表示步长,如 */10 表示每 10 个单位一次。

几个直观的例子:

  • */5 * * * *:每 5 分钟执行一次。
  • 0 2 * * *:每天凌晨 2 点整执行。
  • 30 8 * * 1-5:周一到周五早上 8:30 执行。
  • 0 0 1 * *:每月 1 号 00:00 执行。
  • 0 3 * * 0:每周日(也可以写 7)凌晨 3 点执行。

三、常用 crontab 命令

管理 crontab 的命令非常简单,日常用的就是三个:

  • 编辑定时任务:crontab -e
    打开当前用户的 crontab 编辑器(默认打开 vi 或 nano),在里面逐行写入规则即可。

  • 查看定时任务:crontab -l
    列出当前用户的所有 crontab 条目。

  • 删除所有定时任务:crontab -r
    清空当前用户的全部 crontab 记录。加 -i 会先弹窗确认,推荐 crontab -ri 以防误删。

如果需要以其他用户身份管理,例如 crontab -u username -l,通常需要 root 权限。

四、示例实践

下面用真实可运行的场景把语法串起来。

4.1 每 5 分钟检查一次服务并记录日志

*/5 * * * * /usr/bin/systemctl is-active --quiet nginx || echo "nginx 异常 $(date)" >> /home/user/nginx_check.log

每 5 分钟检查 nginx 是否 active,如果异常就把时间戳写入日志。

4.2 每天凌晨 2:00 备份数据库到 /backup

0 2 * * * /usr/bin/mysqldump -u root -p'your_password' mydb | gzip > /backup/mydb_$(date +\%Y\%m\%d).sql.gz

注意:crontab 里的 % 是特殊字符(被当作物换行符),要写成 \% 才能正常出现在命令中。这是最容易踩的坑之一。

4.3 每月 1 号清理 30 天前的日志文件

0 3 1 * * find /var/log/myapp -name '*.log' -mtime +30 -delete

每月 1 号凌晨 3 点,删除 /var/log/myapp 中 30 天以上的 .log 文件。

4.4 工作日每天早上 9:00 和下午 6:00 各执行一次同步

0 9,18 * * 1-5 /home/user/scripts/sync_data.sh

利用 , 枚举小时、1-5 限定周一到周五。

4.5 把命令输出同时打印到终端和日志文件

实际使用中更推荐在脚本里做好日志,但如果只想在 crontab 一行里完成,可以用 tee:

30 2 * * * /home/user/scripts/nightly_task.sh 2>&1 | tee -a /home/user/logs/nightly.log

五、环境变量与常见坑

5.1 环境不同:PATH 和变量很少继承

这是 crontab 最经典的大坑。你在终端里能跑的命令,放到 crontab 经常「找不到命令」。

原因:cron 启动时只会给一个极简的环境(默认 PATH 通常只有 /usr/bin:/bin),不会加载 ~/.bashrc / ~/.profile。

解法:

  • 命令一律写绝对路径(/usr/bin/python3、/home/user/scripts/xxx.sh)。
  • 在 crontab 顶部显式声明需要的环境变量:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
  • 或者在脚本第一行写 shebang 并用绝对路径调用解释器:#!/bin/bash,然后 chmod +x。

5.2 % 特殊字符

在 crontab 时间字段之后,第一个未转义的 % 会被解释为换行符,后面的内容被当作命令的标准输入。

  • 想输出 100%,必须写成 100\%。
  • 日期格式化 $(date +\%Y-\%m-\%d) 同理,每个 % 都要加 \。

5.3 输出去哪儿了?默认会发邮件

cron 默认会把命令的标准输出和标准错误作为邮件发给任务所属用户。如果服务器没有配置邮件服务(很多云主机默认没装 sendmail/postfix),邮件发不出去,日志就「消失」了,排查起来非常痛苦。

建议写法:在命令末尾显式重定向,把日志写到文件:

* * * * * /home/user/scripts/check.sh >> /home/user/logs/cron.log 2>&1

或者在 crontab 头部设置 MAILTO="" 关闭邮件,自己负责日志。

5.4 任务重叠:上一步还没跑完,下一步又到时间

crontab 本身没有防重叠机制。如果任务要跑 10 分钟,你设的是每分钟执行一次,第 2 分钟到来时它会再开一个副本,最后可能同时跑很多个。

解法:

  • 用 flock 加互斥锁:
* * * * * /usr/bin/flock -n /tmp/myjob.lock /home/user/scripts/myjob.sh
  • 在脚本开头自己用 PID 文件或 pgrep 判断。

5.5 周和日同时限制时是「或」不是「与」

如果你写:

0 2 * * 1

意思是每天都满足(日=任意)且周一满足(周=1),cron 会把它当成「或」:只要其中一个条件命中就会执行。

所以这条实际效果是「每天都执行」,而不是「每周一」。想要「每周一」,日字段填 *、周字段填 1 即可;不要两个都限定具体数字。

5.6 权限与 umask

cron 的 umask 默认通常是 022,这可能导致脚本创建的文件权限和你预期不一样(比如数据库备份文件其他用户可读)。在 crontab 头部显式指定:

UMASK=0077

对涉及敏感数据的脚本尤其重要。

5.7 时区问题

cron 使用系统的时区设置。如果在容器或云主机里时区被设成了 UTC,而你按北京时间写的 0 2 * * *,实际触发时间就差了 8 小时。

确认时区:timedatectl(systemd)或 date。需要时可通过环境变量 TZ 覆盖:

TZ=Asia/Shanghai
0 2 * * * /home/user/scripts/backup.sh

六、调试 crontab 的小技巧

  • 用 date 输出到日志快速验证任务有没有按时跑:
* * * * * echo "cron tick at $(date)" >> /home/user/logs/cron_test.log

先跑一两条最简单的,确认 cron 服务正常、路径和日志都能工作,再接真正任务。

  • 查看系统 cron 日志:

    • systemd 系统:journalctl -u cron 或 journalctl -u crond
    • 传统 syslog:/var/log/cron 或 /var/log/syslog 中搜索 CRON
  • 确认 crond 是否在运行:

systemctl status crond
# 或
systemctl status cron

很多容器里 crond 默认不装也不开机自启,需要先 apt install cron / yum install cronie 并启动。

  • 编辑完成后一定要 crontab -l 确认内容落盘,别只看 vi 退出没报错就以为生效了。

七、总结

  • crontab 的精髓就是五颗星 + 命令,分钟到周,配合 *, ,, -, / 几乎能表达任何周期。
  • 新手最常踩的坑:命令没有用绝对路径、% 没转义、输出被发到无处投递的邮件、任务重叠、日与周的「或」逻辑、时区不一致。
  • 排错三板斧:写死绝对路径 + 显式重定向日志 + 用 flock 防重叠,能解决九成以上的「crontab 为什么没执行」问题。

把上面这些习惯养成之后,crontab 就是你运维和日常自动化里最省心的工具之一。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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