计划任务 - Linux系统计划任务

1. Crond计划任务概述

1.1 什么是计划任务

计划任务类似于我们平时生活中的闹钟。

在Linux系统的计划任务服务crond可以满足周期性执行任务的需求。

crond进程每分钟会处理一次计划任务, 计划任务主要是做一些周期性的任务目前最主要的用途是定时备份数据。

1.2 计划任务类型

类型 说明 命令
at Schedule one-time tasks with at. 一次性调度执行 at
cron Schedule recurring jobs with cron. 循环调度执行 crontab
系统任务 Schedule recurring system jobs. 系统级别的循环任务 /etc/crontab

注意: 所有计划任务执行中的输出都会以邮件的方式发送给指定用户, 除非重定向。

1.3 crond服务

循环调度执行cron,进程每分钟会处理一次计划任务。

1
2
3
4
5
6
# 查看crond服务状态
[root@linux-node1 ~]# systemctl status crond.service

# 查看crond进程
[root@linux-node1 ~]# ps aux |grep crond
root 1201 0.0 0.0 126264 1640 ? Ss 11:15 0:00 /usr/sbin/crond -n

1.4 计划任务分类

计划任务分为以下两种情况:

1. 系统级别的定时任务

  • 清理系统缓存
  • 临时文件清理
  • 系统信息采集
  • 日志文件切割

2. 用户级别的定时任务

  • 定时同步互联网时间
  • 定时备份系统配置文件
  • 定时备份数据库文件

2. crond配置文件详解

2.1 配置文件说明

文件 说明
/etc/crontab Crontab配置文件
/etc/cron.deny 该文件中所列用户不允许使用crontab命令
/var/spool/cron/* 所有用户定时文件都存放此目录,文件以用户名命名
/var/log/cron* 定时任务执行后的日志文件,可用来回溯

2.2 /etc/crontab文件

系统级别的计划任务配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看系统计划任务配置
cat /etc/crontab

# 示例内容
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

2.3 /etc/cron.deny文件

控制哪些用户不能使用crontab命令。

1
2
3
4
5
# 查看被禁止的用户
cat /etc/cron.deny

# 添加禁止用户
echo "username" >> /etc/cron.deny

2.4 /var/spool/cron/目录

用户级别的计划任务文件存储位置。

1
2
3
4
5
6
# 查看所有用户的计划任务
ls -l /var/spool/cron/

# 每个用户的计划任务以用户名命名
# /var/spool/cron/root
# /var/spool/cron/liyanzhao

3. crond计划任务管理

3.1 crontab任务管理

crond任务管理命令。

参数 含义 指定示例
-e 编辑crontab文件内容 crontab -e
-l 查看crontab文件内容 crontab -l
-r 删除crontab文件内容 crontab -r
-u 管理其他用户的计划任务 crontab -u xuliangwei -l
1
[root@linux-node1 ~]# crontab --help

注意: crontab {-l -e}实际上就是在操作/var/spool/cron/username

3.2 crond时间含义

1
2
3
4
5
6
7
8
# Example of job definition:
# .---------------- minute (0 - 59) //分钟
# | .------------- hour (0 - 23) //小时
# | | .---------- day of month (1 - 31) //日期
# | | | .------- month (1 - 12) OR jan,feb,mar,apr //月份
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat //星期
# | | | | |
# * * * * * command to be executed

时间字段说明:

字段 范围 说明
分钟 0-59 每小时的第几分钟执行
小时 0-23 每天的第几小时执行
日期 1-31 每月的第几天执行
月份 1-12 每年的第几月执行
星期 0-7 每周的第几天执行(0和7都表示周日)

特殊字符说明:

字符 说明 示例
* 表示任意的(分、时、日、月、周)时间都执行 * * * * *
- 表示一个时间范围段 0 5-7 * * * (5点到7点)
, 表示分隔时段 0 6,0,4 * * * (周六、日、四)
/n 表示每隔n单位时间 */10 * * * * (每10分钟)

3.3 crond编写示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 每天2:00整
00 02 * * * ls

# 每月1号2:00整
00 02 1 * * ls

# 每年2月14号2:00整
00 02 14 2 * ls

# 每周日2:00整
00 02 * * 7 ls

# 每年6月的周五2:00整
00 02 * 6 5 ls

# 每月14号2:00整或每周日2:00整,这两个时间都执行
00 02 14 * 7 ls

# 每年2月14号2:00整或者每周日2:00整,这两个时间都执行
00 02 14 2 7 ls

# 每天2:00整
00 02 * * * ls

# 每天2:00中的每一分钟 (逻辑错误)
* 02 * * * ls

# 每分钟执行
* * * * * ls

# 2月14号的每分钟(逻辑错误)
* * 14 2 * ls

# 每隔5分钟
*/5 * * * * ls

# 每年1,5,8月的每天2:00整
00 02 * 1,5,8 * ls

# 每月1到8号的2:00整
00 02 1-8 * * ls

4. crond配置编写实例

4.1 crond书写规范

规范1: 为计划任务增加必要的注释

1
2
3
[root@linux-node1 ~]# crontab -l
##time sync by xuliangwei 2018-00-00
*/5 * * * * /usr/sbin/ntpdate time.windows.com &>/dev/null

规范2: 规范计划任务执行脚本存放的路径

1
2
3
[root@linux-node1 ~]# crontab -l
##backup www to /backup xuliangwei 2018-00-00
00 01 * * * /bin/sh /soft/scripts/www_backup.sh &>/dev/null

规范3: 执行shell脚本任务前加/bin/sh, 脚本结尾加&>/dev/null

调试好后应屏蔽debug输出信息,避免产生系统垃圾占用过多inode, 如需输出日志, 可重定向至日志文件。

1
2
3
[root@linux-node1 ~]# crontab -l
####backup www to /backup xuliangwei 2018-00-00
00 01 * * * /bin/sh /soft/scripts/www_backup.sh &>/dev/null

4.2 crond配置编写实例

1
2
3
4
5
6
7
8
9
10
[root@linux-node1 ~]# crontab -e

# 每天凌晨切割nginx日志
00 00 * * * /bin/sh -x /soft/scripts/cut_nginx.sh &> /soft/scripts/log/nginx.log

# 每天5点备份数据库
00 05 * * * /bin/sh -x /soft/scripts/dump_sql.sh &>/soft/scripts/log/mysql.log

# 每5分钟检测数据库是否正常
*/5 * * * * /bin/sh /soft/scripts/start_mysql.sh &>/dev/null

4.3 注意事项

  1. 我们所有的crond服务是运行的程序。而crontab命令用户用来设置定时规则的命令。
  2. crond服务是企业生产工作中常用的重要服务,at很少使用,可以忽略。
  3. 几乎每个服务器都会用到crond服务

5. crond计划任务调试

5.1 调试方法

方法1: 调整任务每分钟执行

检测是否是否正常, 有些任务不要频繁执行。

1
2
# 临时修改为每分钟执行,测试完成后改回原时间
* * * * * /bin/sh /soft/scripts/test.sh

方法2: 调整系统时间然后在检测任务

生产不建议直接使用此方式。

1
2
# 调整系统时间(仅用于测试)
date -s "2024-02-16 02:00:00"

方法3: 执行脚本, 将脚本执行输出写入指定日志文件

观察日志内容是否正常。

1
2
# 在计划任务中重定向输出到日志文件
00 02 * * * /bin/sh /soft/scripts/backup.sh >> /var/log/backup.log 2>&1

方法4: 注意一些任务命令带来的问题

1
2
3
4
5
# 错误示例
echo "xuliangwei" >>/tmp/xlw.log &>/dev/null

# 正确示例
echo "xuliangwei" >> /tmp/xlw.log 2>&1

方法5: 命令使用绝对路径

防止无法找到命令导致定时任务执行故障。

1
2
3
4
5
# 错误:使用相对路径
* * * * * ls

# 正确:使用绝对路径
* * * * * /bin/ls

方法6: 查看/var/log/cron日志进行调试

1
2
3
4
5
# 查看cron日志
tail -f /var/log/cron

# 查看特定时间的日志
grep "backup" /var/log/cron

5.2 调试建议流程

建议: 将需要定期执行的任务写入脚本中, 建立/soft/scripts目录统一存放脚本, 脚本中命令必须使用绝对路径,手动执行脚本检测输出是否正常, 然后将脚本加入计划任务测试, 测试后无问题将脚本输出写入对应的日志文件中即可。

步骤1: 手动执行保留执行命令的正确结果

1
2
# 手动执行命令,确保命令正确
/bin/sh /soft/scripts/backup.sh

步骤2: 编写脚本

  • 脚本需要统一路径/soft/scripts
  • 脚本开头建议填写注释信息, 包括执行时间、周期、任务
  • 脚本内容复制执行成功的命令至脚本文件中(减少每个环节出错几率)
  • 脚本内容尽可能的优化, 使用一些变量或使用简单的判断语句
  • 脚本执行的输出信息不要随意打印, 可以重定向至其他位置保留或丢入黑洞

脚本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
# 脚本名称: backup.sh
# 执行时间: 每天凌晨2点
# 执行周期: 每天
# 任务说明: 备份网站数据
# 作者: xuliangwei
# 日期: 2024-02-16

BACKUP_DIR="/backup/www"
SOURCE_DIR="/var/www/html"
DATE=$(date +%Y%m%d)

mkdir -p ${BACKUP_DIR}
tar czf ${BACKUP_DIR}/www_${DATE}.tar.gz ${SOURCE_DIR}

步骤3: 执行脚本

使用bash执行, 防止脚本没有增加执行权限。

1
2
3
4
# 使用bash执行
/usr/bin/bash /soft/scripts/backup.sh

# 执行命令以及脚本成功后并复制该命令

步骤4: 编写计划任务

  • 加上必要的注释信息, 人、时间、任务
  • 设定计划任务执行的周期
  • 粘贴执行脚本的命令(不要手敲)
1
2
3
4
5
6
# 编辑计划任务
crontab -e

# 添加任务
##backup www to /backup xuliangwei 2024-02-16
00 02 * * * /usr/bin/bash /soft/scripts/backup.sh >> /var/log/backup.log 2>&1

步骤5: 调试计划任务

  • 增加任务频率测试、调整系统时间测试(不能用于生产)
  • 检查环境变量问题、检查crond服务产生日志进行排查
1
2
3
4
5
6
7
8
9
# 临时改为每分钟执行测试
* * * * * /usr/bin/bash /soft/scripts/backup.sh >> /var/log/backup.log 2>&1

# 查看日志
tail -f /var/log/backup.log
tail -f /var/log/cron

# 测试完成后改回原时间
00 02 * * * /usr/bin/bash /soft/scripts/backup.sh >> /var/log/backup.log 2>&1

6. 计划任务实战案例

6.1 案例1: 定时备份数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# 脚本名称: dump_mysql.sh
# 执行时间: 每天凌晨3点
# 任务说明: 备份MySQL数据库
# 作者: xuliangwei
# 日期: 2024-02-16

BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="mydb"
DB_USER="root"
DB_PASS="password"

mkdir -p ${BACKUP_DIR}
/usr/bin/mysqldump -u${DB_USER} -p${DB_PASS} ${DB_NAME} > ${BACKUP_DIR}/${DB_NAME}_${DATE}.sql

# 删除7天前的备份
find ${BACKUP_DIR} -name "*.sql" -mtime +7 -delete

计划任务配置:

1
2
# 每天凌晨3点备份数据库
00 03 * * * /usr/bin/bash /soft/scripts/dump_mysql.sh >> /var/log/mysql_backup.log 2>&1

6.2 案例2: 定时切割Nginx日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
# 脚本名称: cut_nginx.sh
# 执行时间: 每天凌晨0点
# 任务说明: 切割Nginx访问日志
# 作者: xuliangwei
# 日期: 2024-02-16

LOG_DIR="/var/log/nginx"
DATE=$(date -d "yesterday" +%Y%m%d)

# 切割日志
mv ${LOG_DIR}/access.log ${LOG_DIR}/access_${DATE}.log
mv ${LOG_DIR}/error.log ${LOG_DIR}/error_${DATE}.log

# 重新加载Nginx
/usr/bin/kill -USR1 $(cat /var/run/nginx.pid)

# 压缩旧日志
gzip ${LOG_DIR}/access_${DATE}.log
gzip ${LOG_DIR}/error_${DATE}.log

# 删除30天前的日志
find ${LOG_DIR} -name "*.log.gz" -mtime +30 -delete

计划任务配置:

1
2
# 每天凌晨切割nginx日志
00 00 * * * /usr/bin/bash /soft/scripts/cut_nginx.sh >> /var/log/nginx_cut.log 2>&1

6.3 案例3: 定时同步时间

1
2
3
4
5
6
7
8
#!/bin/bash
# 脚本名称: ntp_sync.sh
# 执行时间: 每5分钟
# 任务说明: 同步互联网时间
# 作者: xuliangwei
# 日期: 2024-02-16

/usr/sbin/ntpdate time.windows.com &>/dev/null

计划任务配置:

1
2
# 每5分钟同步时间
*/5 * * * * /usr/bin/bash /soft/scripts/ntp_sync.sh

6.4 案例4: 定时清理临时文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# 脚本名称: clean_tmp.sh
# 执行时间: 每天凌晨4点
# 任务说明: 清理临时文件
# 作者: xuliangwei
# 日期: 2024-02-16

# 清理/tmp目录下7天前的文件
find /tmp -type f -mtime +7 -delete

# 清理/var/tmp目录下30天前的文件
find /var/tmp -type f -mtime +30 -delete

# 清理系统日志(保留7天)
find /var/log -name "*.log" -mtime +7 -delete

计划任务配置:

1
2
# 每天凌晨4点清理临时文件
00 04 * * * /usr/bin/bash /soft/scripts/clean_tmp.sh >> /var/log/clean.log 2>&1

6.5 案例5: 定时监控服务状态

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
# 脚本名称: check_mysql.sh
# 执行时间: 每5分钟
# 任务说明: 检测MySQL服务是否正常
# 作者: xuliangwei
# 日期: 2024-02-16

if ! /usr/bin/systemctl is-active --quiet mysqld; then
/usr/bin/systemctl start mysqld
echo "$(date): MySQL服务已重启" >> /var/log/mysql_monitor.log
fi

计划任务配置:

1
2
# 每5分钟检测数据库是否正常
*/5 * * * * /usr/bin/bash /soft/scripts/check_mysql.sh

7. 计划任务最佳实践

7.1 脚本编写规范

  1. 统一路径: 脚本统一存放在/soft/scripts目录
  2. 添加注释: 脚本开头添加注释信息(时间、周期、任务、作者)
  3. 使用绝对路径: 脚本中所有命令使用绝对路径
  4. 错误处理: 添加错误处理和日志记录
  5. 输出重定向: 合理处理输出,避免产生大量日志

7.2 计划任务配置规范

  1. 添加注释: 每个计划任务添加注释说明
  2. 使用脚本: 复杂任务写入脚本,计划任务调用脚本
  3. 日志记录: 重要任务记录日志
  4. 测试验证: 配置后先测试,确认无误再上线

7.3 环境变量问题

计划任务执行时环境变量可能与用户登录时不同,建议在脚本中设置必要的环境变量。

1
2
3
4
5
6
7
#!/bin/bash
# 设置环境变量
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
export LANG=en_US.UTF-8

# 执行任务
/usr/bin/command

7.4 常见问题处理

问题1: 命令找不到

1
2
3
4
5
# 错误:使用相对路径
* * * * * ls

# 正确:使用绝对路径
* * * * * /bin/ls

问题2: 权限问题

1
2
3
4
5
# 确保脚本有执行权限
chmod +x /soft/scripts/backup.sh

# 在计划任务中使用bash执行
* * * * * /usr/bin/bash /soft/scripts/backup.sh

问题3: 输出邮件问题

1
2
3
4
5
# 重定向输出,避免发送邮件
* * * * * /usr/bin/command &>/dev/null

# 或重定向到日志文件
* * * * * /usr/bin/command >> /var/log/command.log 2>&1

8. 计划任务管理命令总结

8.1 crontab命令

命令 功能 示例
crontab -e 编辑计划任务 crontab -e
crontab -l 查看计划任务 crontab -l
crontab -r 删除计划任务 crontab -r
crontab -u user -e 编辑其他用户的计划任务 crontab -u liyanzhao -e
crontab -u user -l 查看其他用户的计划任务 crontab -u liyanzhao -l

8.2 服务管理命令

命令 功能 示例
systemctl status crond 查看服务状态 systemctl status crond
systemctl start crond 启动服务 systemctl start crond
systemctl stop crond 停止服务 systemctl stop crond
systemctl restart crond 重启服务 systemctl restart crond

8.3 日志查看命令

命令 功能 示例
tail -f /var/log/cron 实时查看cron日志 tail -f /var/log/cron
grep "backup" /var/log/cron 查找特定任务日志 grep "backup" /var/log/cron

9. 计划任务时间表达式速查

9.1 常用时间表达式

表达式 说明
* * * * * 每分钟执行
*/5 * * * * 每5分钟执行
0 * * * * 每小时执行
0 */2 * * * 每2小时执行
0 0 * * * 每天凌晨执行
0 0 * * 0 每周日凌晨执行
0 0 1 * * 每月1号执行
0 0 1 1 * 每年1月1号执行
0 9-17 * * 1-5 工作日上午9点到下午5点每小时执行

9.2 时间表达式示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 每分钟
* * * * * command

# 每小时的第5分钟
5 * * * * command

# 每天凌晨2点
0 2 * * * command

# 每周一凌晨2点
0 2 * * 1 command

# 每月1号凌晨2点
0 2 1 * * command

# 每年1月1号凌晨2点
0 2 1 1 * command

# 每5分钟
*/5 * * * * command

# 工作日上午9点到下午5点每小时
0 9-17 * * 1-5 command

10. 计划任务故障排查

10.1 排查步骤

  1. 检查服务状态: systemctl status crond
  2. 查看计划任务: crontab -l
  3. 查看执行日志: tail -f /var/log/cron
  4. 手动执行脚本: 确认脚本可以正常执行
  5. 检查环境变量: 确认脚本中的环境变量设置正确
  6. 检查权限: 确认脚本有执行权限

10.2 常见错误

错误1: 命令未找到

1
2
3
4
5
# 错误
* * * * * ls

# 正确
* * * * * /bin/ls

错误2: 路径问题

1
2
3
4
5
# 错误:使用相对路径
* * * * * cd /tmp && ls

# 正确:使用绝对路径
* * * * * /bin/cd /tmp && /bin/ls

错误3: 环境变量问题

1
2
3
# 在脚本中设置环境变量
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

11. 计划任务安全建议

11.1 安全配置

  1. 限制用户: 使用/etc/cron.deny限制某些用户使用crontab
  2. 权限控制: 确保脚本文件权限合理
  3. 日志审计: 定期检查计划任务日志
  4. 脚本安全: 避免在计划任务中执行危险命令

11.2 监控建议

  1. 日志监控: 监控/var/log/cron日志
  2. 执行监控: 监控计划任务是否正常执行
  3. 资源监控: 监控计划任务占用的系统资源

实战优化