ubuntu_系统定时任务crontab

ubuntu_系统定时任务crontab.
弄这个主要是为 笔记仓库 全自动化 更新生成 hexo站点 服务, 之前还需要 ssh 连上去执行脚本生成, 现在就让定时任务去定时生成.


前篇


安装 定时任务

如果执行 service cron start 报错 cron: unrecognized service, 则需要安装 cron

1
root@ubuntu-2:~# apt install cron

添加 定时任务

  1. 每分钟将时间追加写入 /tmp/testCron.txt 文件

    1
    2
    3
    4
    5
    6
    7
    8
    # crontab -e


    SHELL=/bin/sh
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

    # m h dom mon dow command
    */1 * * * * date >> /tmp/testCron.txt
  2. 重启 定时任务 服务

    1
    # service cron restart
    • 然后就可以隔几分钟查看一下是否有写入进去

      1
      2
      3
      4
      5
      # cat /tmp/testCron.txt
      Sat Jun 8 11:12:01 UTC 2019
      Sat Jun 8 11:13:01 UTC 2019
      Sat Jun 8 11:14:01 UTC 2019
      Sat Jun 8 11:15:01 UTC 2019

      测试发现如果是 echo 查看的话, 不会输出到控制台显示.


实例说明

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
42
43
44
45
46
47
48
49
50
# m h  dom mon dow   command
# 分 时 天 月 周 命令
## 指定具体执行时间
2 * * * * ls #每个小时的第2分钟执行一次 ls 命令
30 7 * * * ls #每天7:30执行一次 ls 命令
30 20 * * 2 ls #每周二,20:30执行一次 ls 命令(0和7表示星期天)

## 指定间隔时间
*/2 * * * * ls #每隔2分钟执行一次 ls 命令
0 */3 * * * ls #每3小时的 第 0 分钟执行一次,
* */3 * * * ls #每3小时的 每分钟执行一次, 也就是说比如 3~4 点之间, 会执行 60 次, 一般这个不是预期的

## 指定时间段
30 7 3-6 * * ls #每个月的3,4,5,6号的7:30分各执行一次 ls 命令

## 指定多个时间
30 7 3,6 * * ls #每月的3号和6号的7:30分各执行一次 ls 命令

#用date>>~/crontest可以很清楚的看到测试的效果
*/1 * * * * date>>~/crontest

#指定每小时的第5分钟执行一次ls命令
5 * * * * ls

#指定每天的 5:30 执行ls命令
30 5 * * * ls

#指定每月8号的7:30分执行ls命令
30 7 8 * * ls

#指定每年的6月8日5:30执行ls命令
30 5 8 6 * ls

#指定每星期日的6:30执行ls命令【注:0表示星期天,1表示星期1。星期也可以用英文来表示,sun表示星期天,mon表示星期一等。】
30 6 * * 0 ls

#每月10号及20号的3:30执行ls命令【注:“,”用来连接多个不连续的时段】
30 3 10,20 * * ls

#每天8-11点的第25分钟执行ls命令【注:“-”用来连接连续的时段】
25 8-11 * * * ls

#每15分钟执行一次ls命令【即每个小时的第0 15 30 45 60分钟执行ls命令】
*/15 * * * * ls

#每个月中,每隔10天6:30执行一次ls命令【即每月的1、11、21、31日是的6:30执行一次ls 命令。】
30 6 */10 * * ls

#每天7:50以root 身份执行/etc/cron.daily目录中的所有可执行文件【注:run-parts参数表示执行后面目录中的所有可执行文件。】
50 7 * * * root run-parts /etc/cron.daily

Minute Hour Day Month Dayofweek command

分钟 小时 天 月 天每星期 命令

每个字段代表的含义及取值范围如下:

Minute :分钟(0-59),表示每个小时的第几分钟执行该任务

Hour : 小时(1-23),表示每天的第几个小时执行该任务

Day : 日期(1-31),表示每月的第几天执行该任务

Month : 月份(1-12),表示每年的第几个月执行该任务

DayOfWeek : 星期(0-6,0代表星期天),表示每周的第几天执行该任务

Command : 指定要执行的命令(如果要执行的命令太多,可以把这些命令写到一个脚本里面,然后在这里直接调用这个脚本就可以了,调用的时候记得写出命令的完整路径)

“*” ,代表所有的取值范围内的数字;

“/” , 代表”每”(“*/5”,表示每5个单位, 也就是 对 5 求余等于0的时间点, 也就是 0, 5, 10, 15 … 这些时间点)

  • 比如 18 */7 * * * /root/gen_blog.sh , 会在 每天的 07:18:00, 14:18:00, 21:18:00 这些时间点执行

“-” , 代表从某个数字到某个数字(“1-4”,表示1-4个单位);

“,” ,分开几个离散的数字;


命令

1
2
3
4
5
6
7
8
9
10
11
12
13
# service cron start  /*启动服务*/
# service cron stop /*关闭服务*/
# service cron restart /*重启服务*/
# service cron reload /*重新载入配置*/

# 可以通过以下命令查看cron是否在运行(如果在运行,则会返回一个进程ID):
# pgrep cron

# 查看定时任务是否存在和运行
# crontab -l

# 编辑定时任务
# crontab -e

查看日志

  1. 如果系统没有安装 rsyslog 模块, 需要先安装

    1
    # apt install rsyslog
  2. 编辑配置, 去掉相关注释

    1
    2
    3
    # vi /etc/rsyslog.d/50-default.conf

    # 找到cron.log相关行,将前面注释符#去掉,保存退出,重启rsyslog:
  3. 重启 rsyslog 服务

    1
    # service rsyslog  restart
  4. 就可以查看到 日志 /var/log/cron.log

    1
    2
    3
    # vi /var/log/cron.log

    Jun 8 11:45:01 ubuntu-2 CRON[2709]: (root) CMD (/root/gen_blog.sh)

调试定时任务

设置为每分钟执行, 把日志输出到一个地方. 比如 执行 pic_download.sh 日志输出到 aaa.log

1
*/1 * * * * /my_git_repo/qiniuPicture/pic_download.sh >> /my_git_repo/qiniuPicture/aaa.log 2>&1

执行定时任务时一定要设置环境变量

如果不设置, 在 python 脚本中会获取不到环境变量

设置环境变量有两种方式

  1. 设置到用户目录下的 ~/.bash_profile 文件中. 推荐

    1
    2
    3
    export LANG="zh_CN.utf-8"
    export LC_CTYPE="zh_CN.utf-8"
    export PYTHONIOENCODING="utf-8"

    执行的 shell 脚本 pic_download.sh

    1
    2
    3
    4
    #!/bin/bash
    cd $(dirname ${BASH_SOURCE[0]})
    source $HOME/.bash_profile
    python3 pic_download.py
  2. 设置到执行脚本之前 export 环境变量. 执行的 shell 脚本 pic_download.sh

    1
    2
    3
    4
    5
    6
    #!/bin/bash
    cd $(dirname ${BASH_SOURCE[0]})
    export LANG="zh_CN.utf-8"
    export LC_CTYPE="zh_CN.utf-8"
    export PYTHONIOENCODING="utf-8"
    python3 pic_download.py

很多时候安装的程序也会找不到, 所以最好把系统的一些可执行文件所在的目录加入到 ~/.bash_profile 文件中, 如:

1
2
3
4
# 为了 cron 而设, 很多安装的程序都会在这个路径下, 但 定时任务 获取不到, 就必须设置
export PATH=$PATH:/usr/local/bin
BIN_HOME=/usr/local/bin
export BIN_HOME

秒级 定时任务

一般的守护进程都需要 秒级 的重启, 而定时任务最小单位时 分钟, 但可以通过机器实现 秒级 定时任务, 例如: 每 10 秒调用

1
2
3
4
5
6
7
8
9
10
$ crontab -e # 编辑定时任务

* * * * * /root/proc_alive.sh >> /root/check.log 2>&1 &
* * * * * sleep 10; /root/proc_alive.sh >> /root/check.log 2>&1 &
* * * * * sleep 20; /root/proc_alive.sh >> /root/check.log 2>&1 &
* * * * * sleep 30; /root/proc_alive.sh >> /root/check.log 2>&1 &
* * * * * sleep 40; /root/proc_alive.sh >> /root/check.log 2>&1 &
* * * * * sleep 50; /root/proc_alive.sh >> /root/check.log 2>&1 &

$ service cron restart # 重启定时任务

如果多个脚本需要相同的秒级实现, 可以统一一个 执行 shell 脚本a, 把需要调用的其他 shell 脚本丢到 脚本a 中去调用, 脚本a 在定时任务中调用.


shell 添加进系统的环境变量

crontab 并不享有用户的 path, 所以执行 shell 脚本时, 必须在 shell 中添加进系统的环境变量.

  1. 先输出系统的 环境变量 PATH

    1
    2
    # echo $PATH
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/bin
  2. 在 shell 脚本加入 环境变量 PATH

    1
    2
    3
    4
    5
    6
    #!/bin/bash
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/bin
    source $HOME/.bash_profile
    cd $(dirname ${BASH_SOURCE[0]})

    python3 refresh_blog_gen.py

踩坑


定时任务 中某个命令不执行

比如在自动生成 hexo 站点时, git 的命令执行了, 但是 hexo 相关命名没有执行

解决方法参考: hexo generate not working with crontab?

就是再 shell 脚本中, 加入 hexo 命令所在的路径, 如

1
2
PATH=/usr/local/bin/:$PATH
python refresh_blog_gen.py

查看 hexo 命令所在路径

1
2
root@ubuntu-2:~# whereis hexo
/usr/local/bin/

定时任务中 python 获取不到环境变量

被这个坑的有点久, 最终参考这个解决: cronjob cannot find environment variables defined in .bashrc

参考: 执行定时任务时一定要设置环境变量

需要起一个中间 shell 脚本, 设置当前系统的环境变量 到 定时任务 中, 如: pic_download.sh

1
2
3
4
5
# vi pic_download.sh

#!/bin/bash
source $HOME/.bash_profile
python pic_download.py

这样在 python 就能获取到 $HOME/.bash_profile 中的变量

1
2
import os
os.environ.get('QINIU_PIC_HOME')

定时任务中执行 python 报错: UnicodeEncodeError

python3 UnicodeEncodeError: ‘ascii’ codec can’t encode characters cron

参考: https://stackoverflow.com/questions/11735363/python3-unicodeencodeerror-only-when-run-from-crontab

识别不了中文编码, 执行 python 之前需要设置环境变量. 参考: 执行定时任务时一定要设置环境变量

1
2
3
export LANG="zh_CN.utf-8"                                                                            
export LC_CTYPE="zh_CN.utf-8"
export PYTHONIOENCODING="utf-8"

安装语言参考: ubuntu_相关.md 中的 显示中文乱码问题解决


执行 shell 不成功, 手动执行又没问题

基本就是环境变量问题, 在 shell 中执行时获取不到环境变量 or 程序

解决办法: 在 shell 开头加上环境变量配置即可

1
2
3
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/bin
source ~/.bash_profile