Linux定时任务crontab详解
crontab的作用
定时循环任务是由linux上的crond系统服务来控制的,这个系统服务实现是以守护进程的方式实现,守护进程的详解戳文章;
linux提供给用户进程控制定时任务的命令为crontab,由crontab设置后实现用户自定义的定时任务;
crontab的设置
crontab的用法
[root@wefang ~]# crontab [-u username] [-l|-e|-r]
选项与参数:
-u : 只有root才能执行这个任务;
-e : 编辑crontab的任务内容(常用);
-l : 查看crontab的任务内容;
-r : 删除所有的crontab任务,若仅要删除一项,用-e去编辑;
crontab的编辑列表
打开一个腾讯云服务器的crontab列表:
可以看到在crontab中配置了三项定时任务,且定时任务的格式都类似;
具体每项代表含义列表如下:
代表意义 | 分钟 | 小时 | 日期 | 月份 | 周 | 命令 |
---|---|---|---|---|---|---|
数字范围 | 0-59 | 0-23 | 1-31 | 1-12 | 0-7 | 需要执行的命令 |
注意:周的0和7都是代表周日的意思
注意到在上图中,除了数字外,还有特殊符号占据了项的内容,特殊符号的含义如下:
特殊字符 | 代表意义 |
---|---|
* | 代表任何时刻。就是“每”的 意思,如 * * * * * command,就是在crontab中注册了一个每分钟,每小时,每天,每月每周都发生的command; |
, | 用于分隔时段,逗号分隔的数字都会发生。如需要任务在每天8点和12点发生,即命令为 0 8,12 * * * command |
- | 用于一段持续的时间,如需要在8点到12点每个小时都发生一次,即命令为 0 8-12 * * * command |
/n | n是一个数字,代表“每隔”n个时间发生一次,如需要五分钟发生一次 ,即命令为 */5 * * * * command |
crontab的配置
- 允许用户使用crontab,一般有如下两个配置,正常情况下保留一个就ok
- /etc/cron.allow定义可以使用crontab的账号,不在这个文件内的用户就不能使用crontab;
- /etc/cron.deny定义不能够使用crontab的账号,不在这个文件内的用户就可以使用crontab;
- 用户使用crontab创建完定时任务之后,该项任务就被记录到/var/spool/cron中,且内层目录的文件夹是以用户名作为区分的;
- crontab的系统配置文件/etc/crontab和/etc/cron.d,一般我都没管过…所以也不是很清楚;
crond进程
crontab命令由crond进程实现,在重新写crontab命令后,要对crond进程重启服务或重新载入配置才ok;
crond的各项操作如表所示:
命令 | 代表含义 |
---|---|
service crond start | 启动服务 |
service crond stop | 关闭服务 |
service crond restart | 重启服务 |
service crond reload | 重新载入配置 |
service crond status | 查看服务状态 |
crontab命令后的> /dev/null 2 > &1的含义
- 一般定时任务都是作为后台运行> /dev/null用于将crontab后的脚本输出重定向到/dev/null中(丢弃比标准输出),就不会显示在终端;
- 2 > &1,文件描述符的0,1,2分别代表(标准输入stdin,标准输出stdout,错误输出stderr),标准输出与错误输出默认是输出到终端的,因为目前标准输出已经丢弃,错误输出重定向到标准输出,所以也直接被丢弃啦;
crontab遇过的坑
周末写了个init.sh定时脚本监控一个进程是否启动,若没有启动则将进程拉起,若起了多个进程,则将全部进程干掉,重新拉起,每一分钟执行一次;
init.sh的shell代码如下:
#!/usr/bin/env bash
dir_path='/usr/local/'
file_path=${dir_path}"monitor.py"
monitor_num=`ps -ef | grep monitor | grep -v grep | grep -v vim | wc -l`
log_file=`find $dir_path -name "monitor_2019*" | sort -r | head -n 1 | awk -F'/' '{print $NF}'`
echo "init start"
if [ $monitor_num -eq 0 ];then
now=`date '+%Y-%m-%d %H:%M:%S'`
#echo "start monitor at:" $now >> $log_file
#echo $file_path
/usr/bin/python $file_path &
if [ $? == '0' ];then
echo "start monitor success at:" $now >> $log_file
else
echo "start monitor fail at:" $now >> $log_file
fi
elif [ $monitor_num -gt 1 ];then
ps -ef | grep monitor| grep -v grep| cut -c 9-15| xargs kill -9
/usr/bin/python $file_path &
if [ $? == '0' ];then
echo "start monitor success at:" $now >> $log_file
fi
# if montor_num == 1, normal
# do nothing
fi
配置的crontab命令如下:
* * * * * cd /usr/local/monitor.py; /bin/sh init.sh
配置完了之后,发现每分钟这个init.sh都会被触发一次,然后判断monitor进程没有启动;发现monitor进程没有启动后,启动monitor。但是monitor进程一直没有被拉起,然后就一直拉,也没有效果。
手动执行了一下init.sh脚本,发现monitor进程直接被拉起,也没见什么异常,说明init.sh脚本应该没什么问题;
最后定位到问题,是因为没有在init.sh脚本中加入路径:
export PATH=$PATH:/usr/bin/:/sbin/:/usr/sbin/:/bin/
加入了路径之后就ok啦,一切符合预期要求,测试通过,以后如果遇到这样同样的问题,要考虑下,是否是脚本的路径问题,最好都配置一个全路径,就再也不会出错了。