• 【Linux相识相知】任务计划和周期性任务


    在我们的生活中,有的工作是例行的,例如每年一次加薪、每年给女朋友过一次生日、每天上班都要打卡等,有的工作是临时发生的,例如明天朋友要来访,你需要准备午餐等等。

    像很多例行的工作,你一旦忙起来就很容易忘记,这时候就需要人去提醒你,linux的crontab功能就能够排上用场了,例如每年女朋友的生日前一天给你发个邮件提醒你,好让你有所准备。临时发生的事情,例如上面那个例子,明天朋友要来访,在第二天的上午给你发一封邮件提醒你要精心准备午餐。这时候linux的at功能就能派上用场了。那他们之间有什么不一样呢?真的有这么牛x吗?下面我们就来一起看看吧!

    at和crontab简介

    at:一般用于未来某一个时间点去执行一次某某任务,要记住,只执行一次,所有at很适合那些临时的任务;

    crontab:周期性的去运行某任务,所以适合那些周期性的任务。

    电子邮件服务

    在写at和crontab之前,我们先来简单的看一下本地的电子邮件服务----mailx,mailx的用途就是用来发送和接受网络邮件。

    用法(这里只简单的谈一下,以便后面介绍at和crontab,详细的可以见man手册):

    mailx  [-s 'SUBJECT']  username[@hostname]    #使用mail也可以

    每个用户在/var/spool/mail/目录下都有一个以自己名字命令的"邮筒",可以用来接收邮件!

    1.通过交互式的方式生成邮件正文,我们让root用户给frank用户发个邮件:

    [root@localhost ~]# mailx -s "hello frank"  frank@localhost.localdomain  #-s指定邮件标题,本地用户@hostname可以去掉
    how are you?
    I am root!
    .
    EOT

    frank用户收邮件:

    [frank@localhost ~]$ mail
    Heirloom Mail version 12.5 7/5/10.  Type ? for help.
    "/var/spool/mail/frank": 1 message 1 new
    >N  1 root                  Mon Sep  4 11:43  19/654   "hello frank"
    & 1                                         #输入序号即可查看文件内容
    Message  1:
    From root@localhost.localdomain  Mon Sep  4 11:43:30 2017
    Return-Path: <root@localhost.localdomain>
    X-Original-To: frank@localhost.localdomain
    Delivered-To: frank@localhost.localdomain
    Date: Mon, 04 Sep 2017 11:43:30 -0400
    To: frank@localhost.localdomain
    Subject: hello frank     #邮件标题
    User-Agent: Heirloom mailx 12.5 7/5/10     #用户收发邮件的工具程序
    Content-Type: text/plain; charset=us-ascii
    From: root@localhost.localdomain (root)
    Status: R
    
    how are you?                  #邮件正文
    I am root!
    2.使用输入重定向来生成邮件正文,让frank给root回一封,这里可以将文件直接发给root用户。
    我们将/tmp/下写好的的hello.txt文件发给root:
    [frank@localhost tmp]$ mailx -s "hello root" root  < /tmp/hello.txt  #这里我们省去了hostname

    root收邮件并查看:

    [root@localhost ~]# 
    You have mail in /var/spool/mail/root     #看吧!这里会弹出提示,告诉你有一封邮件!
    [root@localhost ~]# 
    [root@localhost ~]# mail
    Heirloom Mail version 12.5 7/5/10.  Type ? for help.
    "/var/spool/mail/root": 1 message 1 new
    >N  1 frank                 Mon Sep  4 11:56  19/629   "hello root"
    & 1
    Message  1:
    From frank@localhost.localdomain  Mon Sep  4 11:56:31 2017
    Return-Path: <frank@localhost.localdomain>
    X-Original-To: root
    Delivered-To: root@localhost.localdomain
    Date: Mon, 04 Sep 2017 11:56:31 -0400
    To: root@localhost.localdomain
    Subject: hello root
    User-Agent: Heirloom mailx 12.5 7/5/10
    Content-Type: text/plain; charset=us-ascii
    From: frank@localhost.localdomain (frank)
    Status: R
    
    I am ok!
    and you?
    
    & q    #q退出
    Held 1 message in /var/spool/mail/root
    3.通过管道生成邮件正文,让root给frank再回一封邮件:
    事先准备好了hello2.txt
    [root@localhost ~]# cat /tmp/hello2.txt | mail -s "hey Frank" frank  #使用mail和mailx都是可以的

    frank来收邮件查看:

    [frank@localhost tmp]$ mail
    Heirloom Mail version 12.5 7/5/10.  Type ? for help.
    "/var/spool/mail/frank": 2 messages 1 new
        1 root                  Mon Sep  4 11:43  20/665   "hello frank"
    >N  2 root                  Mon Sep  4 12:05  19/622   "hey Frank"
    & 2
    Message  2:
    From root@localhost.localdomain  Mon Sep  4 12:05:27 2017
    Return-Path: <root@localhost.localdomain>
    X-Original-To: frank
    Delivered-To: frank@localhost.localdomain
    Date: Mon, 04 Sep 2017 12:05:27 -0400
    To: frank@localhost.localdomain
    Subject: hey Frank
    User-Agent: Heirloom mailx 12.5 7/5/10
    Content-Type: text/plain; charset=us-ascii
    From: root@localhost.localdomain (root)
    Status: R
    
    I am fine too!

    好了,邮件服务就暂时写到这里,想要了解的更详细可见参考man手册,下面我们就来进入正式的主题吧!

     

    at命令

    at命令一般用于临时的任务,只会执行一次,at执行的结果都会以邮件的形式发给提交作业的用户。

    语法: at [OPTION]... TIME
    选项:
        -l:查看作业队列,相当于atq
        -f /path/from/somefile:从指定的文件读取作业任务,而不是交互式的输入
        -d:删除指定的作业,相当于atrm
        -c:查看指定作业的具体内容
        -q:指定队列
    TIME:
       精确的时间:HH:MM [YYYY-mm-dd]    00:13 2017-09-05
       模糊的时间:noon,midnight,teatime,tomorrow
       加:now + #      now + 5 minutes  5分钟后,单位有:minutes  hours days weeks

    下面我们就来使用:

    [root@localhost ~]# at  now + 2 minutes
    at> cat /etc/passwd
    at> <EOT>      #输入<EOT>或者使用ctrl+d
    job 6 at Mon Sep  4 12:26:00 2017

    2分钟后我们收到一封邮件:

    [root@localhost ~]# mail
    Heirloom Mail version 12.5 7/5/10.  Type ? for help.
    "/var/spool/mail/root": 4 messages 1 unread
        1 frank                 Mon Sep  4 11:56  20/640   "hello root"
        2 root                  Mon Sep  4 12:21  17/596   "Output from your job        2"
        3 root                  Mon Sep  4 12:24  15/514   "Output from your job        3"
    >U  4 root                  Mon Sep  4 12:26  36/1561  "Output from your job        6"
    & 4
    Message  4:
    From root@localhost.localdomain  Mon Sep  4 12:26:00 2017
    Return-Path: <root@localhost.localdomain>
    X-Original-To: root
    Delivered-To: root@localhost.localdomain
    Subject: Output from your job        6
    To: root@localhost.localdomain
    Date: Mon,  4 Sep 2017 12:26:00 -0400 (EDT)
    From: root@localhost.localdomain (root)
    Status: RO
    
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    ....(略)

    查看作业队列:

    [root@localhost ~]# at -l   #也可以使用atq
    7    Mon Sep  4 12:29:00 2017 a root

    从指定的文件去读取作业任务:

    [root@localhost ~]# at -f myat.txt  12:36
    job 9 at Mon Sep  4 12:36:00 2017
    [root@localhost ~]# atq   #查看作业队列,相当at -l
    9    Mon Sep  4 12:36:00 2017 a root 

    使用-c查看指定作业的具体内容:

    [root@localhost ~]# at -c 10
    #!/bin/sh
    # atrun uid=0 gid=0
    # mail root 0
    umask 22
    XDG_SESSION_ID=9; export XDG_SESSION_ID
    HOSTNAME=localhost.localdomain; export HOSTNAME
    SELINUX_ROLE_REQUESTED=; export SELINUX_ROLE_REQUESTED
    SHELL=/bin/bash; export SHELL
    HISTSIZE=1000; export HISTSIZE
    SSH_CLIENT=192.168.122.1 62021 22; export SSH_CLIENT
    SELINUX_USE_CURRENT_RANGE=; export SELINUX_USE_CURRENT_RANGE
    SSH_TTY=/dev/pts/0; export SSH_TTY
    USER=root; export USER
    LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:; export LS_COLORS
    MAIL=/var/spool/mail/root; export MAIL
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin; export PATH
    PWD=/root; export PWD
    LANG=en_US.UTF-8; export LANG
    SELINUX_LEVEL_REQUESTED=; export SELINUX_LEVEL_REQUESTED
    HISTCONTROL=ignoredups; export HISTCONTROL
    SHLVL=1; export SHLVL
    HOME=/root; export HOME
    LOGNAME=root; export LOGNAME
    SSH_CONNECTION=192.168.122.1 62021 192.168.122.128 22; export SSH_CONNECTION
    LESSOPEN=||/usr/bin/lesspipe.sh %s; export LESSOPEN
    XDG_RUNTIME_DIR=/run/user/0; export XDG_RUNTIME_DIR
    cd /root || {
         echo 'Execution directory inaccessible' >&2
         exit 1
    }
    ${SHELL:-/bin/sh} << 'marcinDELIMITER02cdeaba'
    echo "hello"
    cat /tmp/hello.txt
    cat /etc/passwd
    具体内容
    这里包括了很多的环境变量,大家可以注意一下这里的PATH,有的情况我们运行的命令不在这个PATH所包含的路径下面,所以写在作业里面的命令建议使用绝对路径。
    在/etc/目录下有这么一个文件,at.deny,写在这个文件里面的用户是不能使用at的。有的情况下不存在at.deny而是存在at.allow,那么只有在at.allow里面的用户才能使用at,如果两个文件都不存在的话,则只用root用户可以使用at。
    除了at命令以外,还有命令是batch,batch会让系统自行选择在系统资源较空闲的时候去执行指定的任务(when the load average drops below 0.8, or the value specified in the invocation of atd.)大致意思就是当平均负载低于0.8的时候。
    可以使用uptime查看平均工作负载(CPU在单位时间点里所负责的工作数量):如果一个程序一直让CPU进行不停的运算,那么此时CPU的工作负载可能就已经达到了100%,也就是1,当我们运行两个这样的程序,那么工作负载可能就会变成2,那么CPU就需要在不同的任务之间切换啦!
    [root@localhost ~]# uptime
     12:57:06 up  5:41,  3 users,  load average: 0.00, 0.01, 0.05  #好吧,现在几乎没有负载
    
    [root@localhost ~]# batch 
    at> /usr/bin/updatedb
    at> <EOT>
    job 12 at Mon Sep  4 12:51:00 2017

    同样batch同样也可以使用atq和atrm来管理。

    周期性任务crond

    循环周期性的任务是由cron(crond)这个系统服务控制的,因为linux上原本就有很多的循环周期性的任务,例如系统会周期性的删除/tmp目录下的临时文件。linux也给管理员和用户提供了控制循环周期性任务的命令——crontab。

    服务程序cronie提供了crond守护进程及相关的辅助工具:

    [frank@localhost ~]$ rpm -q cronie
    cronie-1.4.11-14.el7_2.1.x86_64
    确保crond守护进程(daemon)处于运行状态
    在centos7中:
    [root@localhost ~]# systemctl status crond.service
    ● crond.service - Command Scheduler
       Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
       Active: active (running) since Thu 2017-08-10 07:16:37 EDT; 3 weeks 4 days ago
     Main PID: 682 (crond)
       CGroup: /system.slice/crond.service
               └─682 /usr/sbin/crond -n
    
    Aug 10 07:16:37 localhost.localdomain systemd[1]: Started Command Scheduler.
    Aug 10 07:16:37 localhost.localdomain systemd[1]: Starting Command Scheduler...
    Aug 10 07:16:37 localhost.localdomain crond[682]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 8% if used.)
    Aug 10 07:16:37 localhost.localdomain crond[682]: (CRON) INFO (running with inotify support)

    在centos6中使用:

    [root@localhost ~]# service crond status    #centos7也支持
    在/etc/目录下存在cron.deny,写入其中的用户不能够使用crontab命令,有的时候不存在cron.deny而存在的是cron.allow,则只有在其中的用户才能使用crontab命令。如果两个文件都存在cron.allow的优先级要比cron.deny的优先级高。

     向crond提交作业的方式不同于at,它需要使用专用的配置文件,此文件有固定的格式,不建议使用文本编辑器直接编辑,要使用crontab。文本编辑器编辑保存退出时不会检查语法错误,而使用crontab保存退出会检查语法错误。

    cron的任务分为两类:

    1.系统cron任务,主要用户实现系统自身的维护,一般手动编辑/etc/crontab文件,如果修改后不能马上执行,可以手动的重启这个服务 systemctl restart crond;

    2.用户cron任务,一般使用crontab命令。

    好的,我们现在来看一下系统cron的配置文件/etc/crondtab吧!

    [root@localhost ~]# 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
    注意:
    (1)每一行定义一个周期性的任务,共七个字段:
         *  *  *  *  *:定义周期性的时间
         user-name:运行任务的用户身份
         command to be executed:任务
    (2)此处的环境变量不同于用户登录后获得的环境,因此建议使用绝对路径,或者之定义PATH路径
    (3)执行结果邮件发送给MAILTO指定的用户。
    周期时间表示法则:
    (1)特定值
              给定时间点有效取值范围内的值
              注意:day of week 和day of mouth一般不同时使用
    (2)*
              给定时间点有效取值范围内的所有值,表示每...
    (3)离散取值
               在时间点上使用逗号分隔的多个值:#,#,#
    (4)连续取值
               在时间点上使用逗号分隔的多个值:#-#
    (5)在指定时间上,定义步长
               /#,#即步长
    注意:
    (1)指定的时间点不能被步长真出时,其意义将不复存在;
    (2)最小时间单位为分钟,想完成秒级人物,的需要额外借助其他的机制。

    示例:

    (1) 3 * * * *:每小时执行一次;每小时的第3分钟;
    (2) 3 4 * * 5:每周执行一次;每周5的4点3分;
    (3) 5 6 7 * *:每月执行一次;每月的7号的6点5分;
    (4) 7 8 9 10 *:每年执行一次;每年的10月9号8点7分;
    (5) 9 8 * * 3,7:每周三和周日的8点7分
    (6) 0 8,20 * * 3,7:每周三和周日的20点和20点8分执行;
    (7) 0 9-18 * * 1-5:每周一到周五的早上9点到18点
    (8) */5 * * * *:每5分钟执行一次某任务;
    当给用户创建一个周期性的任务的时候,会在/var/spool/cron生成一个与其用户名相同的配置文件。
    下面就来讲一下crontab命令:
    语法:crontab  [OPTIONS]
    OPTIONS:
        -e:编辑任务
        -l:列出所有任务
        -r:移除所有的任务,即删除/var/spool/cron/USERNAME文件
        -i:在使用-r选项移除所有任务提示用户
        -u user:root用户可为指定用户管理cron任务
    下面我们就来举个例子吧!
    比如每分钟打印一个echo:
    [frank@localhost ~]$ crontab -e
    no crontab for frank - using an empty one
    
    * * * * * echo "hello"

    列出所有的任务:

    [frank@localhost ~]$ crontab -l
    * * * * * echo "hello"

    移除所有的任务:

    [frank@localhost ~]$ crontab -r
    [frank@localhost ~]$ crontab -l
    no crontab for frank

    运行的结果以邮件通知给当前的用户,如果拒绝接受邮件,可以使用输出重定向:

     COMMAND > /dev/null

    注意:定义COMMAND时,如果命令需要用到%,需要对其转义,但放置于单引号中的%不用转义。

    crond服务读取配置文件的位置:

    一般来说,crond预设有三个地方会有执行的脚本配置,他们分别是:

    /etc/crontab

    /etc/cron.d/*

    /var/spool/cron/*

    前两个是与系统运作有关系,最后一个主要用户用自己。

    下面我们来看一下/etc/cron.d/目录下的文件吧!

    [root@localhost ~]# ll /etc/cron.d/
    total 4
    -rw-r--r--. 1 root root 128 Mar 31  2016 0hourly
    [root@localhost ~]# cat /etc/cron.d/0hourly 
    # Run the hourly jobs
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    01 * * * * root run-parts /etc/cron.hourly  #run-parts脚本会在大约5分钟内随机选择一个时间去执行/etc/cron.hourly内的所有文件
    [root@localhost ~]# cat /etc/cron    #细心的朋友会发现etc目录下还有很多关于crond的文件
    cron.d/       cron.daily/   cron.deny     cron.hourly/  cron.monthly/ crontab       cron.weekly/ 

    思考:某任务在指定的时间因关机未能执行,下次开机会不会自动执行?

    答案:不会!.

    如果期望某时间因故未能按时执行,下次开机后无论是否到了相应时间点都要执行一次,可使用anacron实现, /etc/ 底下其实还有 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/,那三个目录是代表每日、每周、每月各执行一次的意思,跟 /etc/cron.hourly/ 不太一样的是,这三个目录是由 anacron 所执行的,而 anacron 的执行方式则是放在/etc/cron.hourly/0anacron 里面的。

    最后的总结

    • 个人的行为推荐使用 crontab -e:如果你只是根据自己的个人需求来运行周期性的任务,而不想被其他的用户看到,建议使用crontab -e,/etc/crontab文件是大家都能读取的哦!
    • 系统维护管理推荐使用vim /etc/crontab:如果你的这个周期性的任务是系统几倍的,而且非常的重要,为了让方便管理和容易追踪,建议直接写入/etc/crontab;
    • 自己开发的软件使用vim /etc/cron.d/newfile:如果你想要运行自己的开发的软件,那么最好的是使用全新的配置文件,并放置在/etc/cron.d目录内即可。
  • 相关阅读:
    eclipse建立工作集管理项目
    echarts-x
    GeoJSON
    mysql 5.7 root password 过期
    kubernetes centos7
    JestClient
    树莓派镜像制作
    docker run elasticsearch
    vm.max_map_count
    远程访问jupyter notebook
  • 原文地址:https://www.cnblogs.com/liubinsh/p/7477461.html
Copyright © 2020-2023  润新知