Crontab 使用注意事项(精讲版)
(1)、注意环境变量问题
有时我们创建了一个crontab,但是这个任务却无法自动执行,而手动执行这个任务却没有问题,这种情况一般是由于在crontab文件中没有配置环境变量引起的。
(2)注意清理系统用户的邮件日志
可以在crontab文件中设置如下形式,忽略日志输出:
0 */3 * * * /usr/local/apache2/apachectl restart >/dev/null 2>&1
(3)、系统级任务调度与用户级任务调度
系统级任务调度主要完成系统的一些维护操作(比如定时重启机器),用户级任务调度主要完成用户自定义的一些任务,可以将用户级任务调度放到系统级任务调度来完成(不建议这么做),但是反过来却不行。
(1)环境变量问题 ⚠️(最高频坑)
现象
# 手动执行 ✅
$ /opt/scripts/backup.sh
备份成功!
# crontab自动执行 ❌
没有备份文件,日志为空
根本原因
cron 执行时的环境变量极其精简,只有:
SHELL=/bin/sh
PATH=/usr/bin:/bin
HOME=/root
LOGNAME=root
而你手动执行时有完整的 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/java/bin...
解决方案(3选1)
方案1:脚本内重新定义PATH(推荐)
#!/bin/bash
# 在脚本开头加入
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATH
# 或者直接写绝对路径
/usr/bin/mysqldump -uroot db > /backup.sql
方案2:crontab 文件全局定义
# crontab -e 第一行写入
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 * * * /opt/scripts/backup.sh
方案3:source 用户环境变量
0 2 * * * . /etc/profile; /opt/scripts/backup.sh
# 或
0 2 * * * source ~/.bashrc; /opt/scripts/backup.sh
(2)邮件日志轰炸 📧(必做优化)
默认行为
每个 cron 任务执行后,只要有输出,系统就会发邮件给用户:
You have new mail in /var/spool/mail/root
后果:长期积累导致 /var 分区爆满,系统报警
根治方案
方案1:丢弃所有输出(安静模式)
# >/dev/null 2>&1 是标准写法
0 2 * * * /opt/scripts/backup.sh >/dev/null 2>&1
# 简写形式(bash支持)
0 2 * * * /opt/scripts/backup.sh &>/dev/null
方案2:只记录错误(生产推荐)
# 正常日志不输出,错误才记录
0 2 * * * /opt/scripts/backup.sh >/dev/null 2>>/var/log/backup_error.log
方案3:自定义日志文件(调试用)
# 所有输出都记录
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
方案4:彻底关闭邮件(全局)
# 在 crontab 开头添加
MAILTO=""
0 2 * * * /opt/scripts/backup.sh
(3)系统级 vs 用户级 🏢(权限铁律)
核心区别
| 对比项 | 用户级 (crontab -e) | 系统级 (/etc/crontab) |
|---|---|---|
| 执行用户 | 当前用户 | 可指定任意用户 |
| 配置文件 | /var/spool/cron/用户名 | /etc/crontab、/etc/cron.d/* |
| 修改权限 | 各用户自己 | 仅root |
| 格式 | 分 时 日 月 周 命令 | 分 时 日 月 周 用户 命令 |
| 应用场景 | 应用备份、业务脚本 | 系统日志切割、服务监控 |
常见错误与解决方案
❌ 错误:系统级任务写了用户级格式
# 写在了 /etc/crontab 里,但没写用户名
0 2 * * * /opt/scripts/backup.sh
# 报错:任务不会执行,cron解析失败
✅ 正确:系统级必须加用户名
0 2 * * * root /opt/scripts/backup.sh
❌ 错误:反向调用(用户级调用系统任务)
# 普通用户执行系统维护任务
0 2 * * * /etc/cron.daily/logrotate
# 可能失败:权限不足
✅ 正确:只能系统级调用用户任务
# /etc/crontab 里以普通用户身份执行
0 2 * * * www-data /home/www/scripts/clear_cache.php
实战原则
- 系统任务 → 放系统级(/etc/crontab 或 /etc/cron.d/)
- 业务任务 → 使用应用户(crontab -e)
- 权限不够 → 找root,不要自己硬改系统级
四、其他要命坑 💀
4.1 % 百分号必须转义
# ❌ 错误
0 2 * * * echo $(date +%Y%m%d) >> /tmp/test.log
# cron会截断%后面的内容
# ✅ 正确(加反斜杠)
0 2 * * * echo $(date +\%Y\%m\%d) >> /tmp/test.log
# ✅ 或在脚本里处理(推荐)
0 2 * * * /opt/scripts/test.sh # 脚本内写%
4.2 任务太长被截断
# ❌ 一行写太长(>1000字符可能被截)
0 2 * * * /usr/bin/rsync -avz --password-file=/etc/rsync.pass --exclude-from=/etc/rsync.exclude --delete /data/ backup@10.0.0.1::backup/
# ✅ 拆成脚本
0 2 * * * /opt/scripts/rsync_backup.sh
4.3 脚本权限问题
# 脚本必须可执行
chmod +x /opt/scripts/backup.sh
# 且对执行用户有读权限
chmod 755 /opt/scripts/backup.sh
4.4 路径依赖问题
# ❌ 用了相对路径
0 2 * * * ./backup.sh # cron不知道当前目录是哪里
# ✅ 绝对路径
0 2 * * * /opt/scripts/backup.sh
五、生产环境最佳实践 ✅
# /etc/cron.d/app_backup (系统级,规范管理)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
SHELL=/bin/bash
# MySQL备份 - root执行,日志记录错误
0 2 * * * root /opt/scripts/backup_mysql.sh >> /var/log/backup/mysql.log 2>&1
# Nginx日志切割 - 使用系统logrotate
5 0 * * * root /usr/sbin/logrotate /etc/logrotate.conf >/dev/null 2>&1
# 磁盘报警 - www用户执行
*/10 * * * * www-data /opt/scripts/disk_alert.py >/dev/null 2>&1
一句话总结
PATH要全、日志要丢、用户要写、%要转义、绝对路径、脚本先测 → 6条记牢,cron不崩!
发表回复