# 定时任务

# at

:用于设置一次性的定时任务。

  • 定时任务是指在某些时刻执行某些命令。

# 用法

  • 命令:
    $ at
        11:30 2019-08-16 < run.sh  # 将.sh 脚本的内容设置成定时任务
        -l                         # 显示所有尚未执行的任务
        -c <任务序号>               # 显示某个任务的内容
        -r <任务序号>               # 删除一个任务
    
    • 当一次性的定时任务被执行或超时之后,就会被从任务表删除。
  • 例:将要执行的命令通过管道符传给 at
    echo "systemctl restart docker" | at 23:00
    
  • at 指定的时间可以是多种格式:
    at 23:00           # 在今天的指定时刻(如果已超过该时刻,则定位到明天的该时刻)
    at now + 3 minutes # 在 3 分钟之后
    at now + 3 hours   # 在 3 小时之后
    at 23:00 + 3 days  # 在 3 天之后的 23:00
    

# crontab

:用于设置定时执行的任务。

  • 在 Linux 主机上,默认会启动 crond 服务,没有的话就执行 systemctl start crond 启动。
    • 在容器中,建议执行 /usr/sbin/crond -i ,作为 daemon 进程启动。
  • 每过一分钟,crond 就会检查一次配置文件中的所有定时任务。如果某个任务的定时时间与当前时刻匹配,则创建一个子进程去执行它。

# 命令

$ crontab
          -e        # 编辑当前用户的任务
          -u <user> # 编辑指定用户的任务
          -l        # 显示任务内容
          -r        # 删除任务内容

# 配置

  • crond 会读取以下路径的配置文件:

    /var/spool/cron/    # 该目录下存在与各个用户同名的文件,用于保存用户用 crontab -e 命令编辑的定时任务
    /etc/crontab        # 保存系统的定时任务,默认为空
    /etc/cron.d/        # 保存系统的定时任务
    
    /etc/cron.hourly/   # 被 /etc/cron.d/ 调用,每小时执行一次
    /etc/cron.daily/    # 老版本的 daily、monthly、weekly 是被 /etc/cron.d/ 调用,现在是被 anacron 进程调用
    /etc/cron.monthly/
    /etc/cron.weekly/
    
  • 用户可以用 crontab -e 命令编辑自己的定时任务,格式如下:

    */1 * * * *  echo hello &>> /var/log/cron   # 每分钟执行一次,并记录输出内容
    0 0 * * 6,0  echo hello &> /dev/null        # 在周六、周日的 00:00 时刻执行任务,并丢弃输出
    0 * * * 1-5  echo hello                     # 在周一至周五,每小时执行一次任务
    @reboot      /root/init.sh                  # 每次重启时执行一次
    
    • 用 # 声明单行注释。
    • 每行定义一条定时任务,格式为 <time> <command>
    • 定时任务的 time 包含五个参数:
      min       # 分钟,取值为 0~59
      hour      # 小时,取值为 0~23
      day       # 日期,取值为 1~31
      month     # 月份,取值为 1~12
      weekday   # 周几,取值为 0~7 ,其中 0、7 都表示周日
      
      • 将参数填写为 * 代表没有限制,只要符合其它条件就行。
      • 如果同时填写了 day、weekday ,则只要符合其中一个参数就算匹配。
      • 例:
        • 0 * * * * 表示到 **:00 时刻执行一次,即每小时的第一分钟执行一次,相当于 0 */1 * * *
        • * */1 * * * 表示每小时的每分钟执行一次。
        • */1 表示每 1 个单位时间一次,等价于 *
      • 最小的时间精度为分钟,因此每个定时任务每分钟最多执行一次。如果需要每分钟执行多次,可采用以下方案:
        • 编写一个 shell 脚本,循环运行,每隔几秒执行一次定时任务。
        • 创建多个同样功能的定时任务,每分钟延迟不同时间再执行:
          * * * * *   /root/test.sh
          * * * * *   ( sleep 30; /root/test.sh )
          
    • crond 在执行任务时:
      • 会切换到用户的家目录。
      • 只会加载很少的环境变量,比如 PATH=/usr/bin:/bin
        因此,填写待执行的命令时,应该尽量使用绝对路径,避免找不到文件。或者先执行 source /etc/profile
  • /etc/cron.d/ 目录下保存了系统的定时任务。格式如下:

    SHELL=/bin/bash                       # 声明少量的环境变量
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root                           # 将命令输出的 stdout、stderr 发送到邮箱 /var/mail/root
    
    0 * * * *   root    echo hello        # 每行的格式为:执行时间 + 执行用户 + 待执行的命令
    
  • crond 会在 /var/log/cron 文件中记录执行的每个任务、执行时刻,如下:

    Jul  3 11:01:01 localhost CROND[4701]: (root) CMD (run-parts /etc/cron.hourly)    # 执行 /etc/cron.hourly
    Jul  3 11:01:01 localhost CROND[4699]: (root) CMD (echo hello &> /dev/null)       # 执行用户自定义的任务
    Jul  3 11:01:01 localhost run-parts(/etc/cron.hourly)[4701]: starting 0anacron
    Jul  3 11:01:01 localhost run-parts(/etc/cron.hourly)[4712]: finished 0anacron
    Jul  3 11:01:14 localhost crontab[4749]: (root) BEGIN EDIT (root)                 # root 用户执行了 crontab -e 命令
    Jul  3 11:01:16 localhost crontab[4749]: (root) END EDIT (root)
    
    • 该文件不会记录定时任务输出的 stdout、stderr 。
    • 该文件每过 7 天就会归档一次,最多保存最近一个月的记录。如下:
      [root@CentOS ~]# ls -lh /var/log/cron*
      -rw------- 1 root root 148K 73 13:45 /var/log/cron
      -rw------- 1 root root 192K 67 03:21 /var/log/cron-20200607
      -rw------- 1 root root 192K 614 03:30 /var/log/cron-20200614
      -rw------- 1 root root 192K 621 03:49 /var/log/cron-20200621
      -rw------- 1 root root 192K 628 03:35 /var/log/cron-20200628
      

# 登录时执行脚本

  • /etc/profile

    • 主要包含 PATH 等环境变量的定义语句,还会调用脚本 /etc/profile.d/*.sh 。
  • /etc/bashrc

    • 不会自动执行,只会被 ~/.bashrc 调用。
    • 主要包含一些函数、 alias 的定义语句。
    • /etc/profile、/etc/bashrc 两个脚本是 Linux 自带的。
      • 新建一个用户时,默认会给它创建 ~/.bashrc、~/.bash_profile、~/.bash_logout 三个脚本。
  • ~/.bashrc

    • 当用户创建交互模式的 shell 时自动执行。
    • 其默认内容如下,会调用 /etc/bashrc :
      if [ -f /etc/bashrc ]; then
          . /etc/bashrc
      fi
      
    • 例:
      [root@CentOS ~]# bash            # 交互模式,执行顺序如下
      /root/.bashrc start
      /etc/bashrc start
      /etc/bashrc end
      /root/.bashrc end
      
      [root@CentOS ~]# bash -c pwd     # 非交互模式,一个也不会执行
      /root
      
  • ~/.bash_profile

    • 当用户创建 login shell 时自动执行。
    • 其默认内容如下,会调用 ~/.bashrc :
      if [ -f ~/.bashrc ]; then
          . ~/.bashrc
      fi
      
      PATH=$PATH:$HOME/.local/bin:$HOME/bin
      export PATH
      
  • ~/.bash_logout

    • :当用户退出 login shell 时自动执行。
    • 默认内容为空。
  • 例:

    • 通过 su 切换用户时,没有创建 login shell ,所以只会执行 ~/.bashrc 。相当于直接执行 bash 创建一个普通 shell 。
    • 通过 su - 切换到当前用户时,创建了 login shell ,所以会执行 /etc/profile、~/.bash_profile 。
    • 当用户退出一个普通 shell 时不会执行上述任何脚本。