crontab 就该这么用
crontab 就该这么用适合自己写定时任务的开发 / 运维。从语法到常见坑再到实际业务任务。crontab 能干什么# 每天 3 点切日志03* * * /opt/scripts/log-rotate.sh# 每 5 分钟检查一次服务状态*/5 * * * * /opt/scripts/health-check.sh# 每周一 9 点发周报09* *1/opt/scripts/weekly-report.sh就是把手动定期做的事交给系统自动跑。语法5 个时间位 命令* * * * * 要执行的命令 │ │ │ │ │ │ │ │ │ └─── 星期几 (0-7, 0和7都是周日) │ │ │ └─────── 月份 (1-12) │ │ └─────────── 日期 (1-31) │ └─────────────── 小时 (0-23) └─────────────────── 分钟 (0-59)直接看例子就懂了03* * *# 每天凌晨 3:00308* * *# 每天 8:3009* *1# 每周一 9:00001* *# 每月 1 号 0:00*/15 * * * *# 每 15 分钟0*/2 * * *# 每 2 小时的整点09-18 * * *# 每天 9 点到 18 点每个整点0,309,18* *1-5# 工作日 9:00、9:30、18:00、18:30记法位置允许值特殊符号分钟0-59*/N每 N 分钟N,M多个值小时0-23*/N每 N 小时日期1-311,151 号和 15 号月份1-12*/2每两个月星期0-71-5周一到周五开始用编辑任务crontab-e第一次会提示选编辑器vim/nano后面改了任务保存即生效不需要重启。查看现有任务crontab-l删除所有任务crontab-r注意-r没有确认提示删了就没了。可以用别名叫alias crontabcrontab -i让它先问一下。三大常见坑坑一环境变量不继承你终端能跑的命令放 crontab 里可能跑不起来。因为 crontab 的 PATH 极简/usr/bin:/bin你装的/usr/local/bin/或自己编译的工具找不到。解决在脚本或 crontab 里写绝对路径# crontab 里写绝对路径03* * * /usr/local/bin/node /opt/scripts/task.js或者在 crontab 顶部定义环境变量PATH/usr/local/bin:/usr/bin:/binSHELL/bin/bashHOME/home/user03* * * ./my-script.sh# 现在可以写相对路径了也可以在任务里显式加载 profile03* * *source~/.bashrc./my-script.sh坑二百分号 % 是特殊字符crontab 里%会被转成换行符。如果你写了03* * *echoToday is$(date%Y%m%d)/tmp/log执行时%Y会被替换变成语法错误。解决%前面加反斜杠转义03* * *echoToday is$(date\%Y\%m\%d)/tmp/log或者把命令写成脚本任务里只调脚本。坑三任务执行了但没有输出默认 crontab 会尝试发邮件到本地 root 邮箱但大多数机器没配邮件服务输出就丢了。解决把输出重定向到文件03* * * /opt/scripts/backup.sh/var/log/backup.log21是追加21把错误信息也写进去。如果只想保留最新一次的输出03* * * /opt/scripts/backup.sh/var/log/backup.log21单个是覆盖。不需要看输出的任务直接丢到黑洞03* * * /opt/scripts/backup.sh/dev/null21实用任务模版1. 进程保活# 每 2 分钟检查一次 nginx 是否存活挂了就拉起*/2 * * * * pgrep nginx/dev/null||systemctl start nginx2. 磁盘清理# 每天 4 点删掉 7 天前的临时文件04* * *find/tmp-typef-mtime7-delete04* * *find/var/log/myapp-name*.log.*-mtime30-delete3. 数据库备份# 每天凌晨 2 点备份数据库02* * * mysqldump-uroot -ppasswordmydb|gzip/backup/mydb-$(date\%Y\%m\%d).sql.gz注意密码放 crontab 里不安全。建议写到/etc/mysql/.my.cnf里用chmod 600保护然后命令只写mysqldump mydb。4. 证书过期检查# 每周一检查证书还剩多少天09* *1echo|openssl s_client-connectmyapp.com:4432/dev/null|openssl x509-noout-enddate|mail-sCert expiryadmincompany.com5. 服务状态日报# 每天 8:00 发一条机器状态08* * *echoLoad:$(uptime)/var/log/daily-status.log怎么确认任务跑了没有看系统日志通用grepCRON /var/log/syslog|tail-20# CentOS 上grepCROND /var/log/cron|tail-20能看到(root) CMD (/opt/scripts/backup.sh)这样的记录。看任务自己的日志如果加了 /var/log/backup.log直接看这个文件。系统级别的定时任务上面讲的crontab -e是用户级别的。除此之外还有路径用途/etc/crontab系统级 crontab格式多一个用户名位/etc/cron.d/放第三方软件的定时任务配置文件/etc/cron.daily/每天由run-parts自动跑一次的脚本/etc/cron.hourly/每小时跑一次/etc/cron.weekly/每周跑一次/etc/cron.monthly/每月跑一次系统运行时间由/etc/anacrontab控制防止机器关机时跳过了任务。如果想定时跑但不想自己配放脚本到/etc/cron.daily/就行。注意文件名不能带.run-parts 会忽略含点的文件。替代方案systemd Timer如果你的系统用 systemd可以用 timer 替代 crontab。好处是精度可到秒级、与 systemctl 集成更好# /etc/systemd/system/backup.service[Unit]DescriptionDatabase Backup[Service]TypeoneshotExecStart/usr/bin/mysqldump mydb|gzip/backup/mydb-%H%M%S.sql.gz# /etc/systemd/system/backup.timer[Unit]DescriptionRun backup daily[Timer]OnCalendardailyPersistenttrue# 如果错过了开机后立即跑[Install]WantedBytimers.targetsystemctlenable--nowbackup.timer# 启用并启动systemctl list-timers# 查看所有定时任务但是这个需要写两个文件简单场景 crontab 一条命令就够了。任务复杂了再考虑 systemd timer。总结要点怎么做看懂语法5 个星号 分 时 日 月 周环境变量脚本里写绝对路径% 问题加反斜杠转义日志重定向到文件确认执行grep CRON /var/log/syslog日常使用就是crontab -e→ 加一行 → 确认日志里有记录 → 搞定。