crontab

程序部署在Linux系统之中,很可能会用到crontab,但是呢,写好的定时任务,可能因为种种错误方式,并没有按着预定的方式运行,如何写出正确的、健壮的定时任务。做一下总结。

入门

原则

  • 1、执行的时候,先cd到目录,最稳妥,防止引入了相对变量的文件路径。
  • 2、加上环境变量,尤其是PATH,有时,居然连/usr/local/bin都不在环境变量中。故,最好自己设置一下。
  • 3、测试,测试的时候,跳到cd /路径,再执行,看看能否正常执行。
  • 4、测试的时候,直接清空 PATH,只加有关的PATH。(待验证)

编写格式

我们假定,脚本执行的时候,没有任何环境变量,没有直接cd 到项目目录中。

# 先进入目录,再执行,都加上绝对路径
40 17 * * * cd /yd/td/shell && /usr/local/php73/bin/php summary.php
# 下载
*/5 * * * * /bin/curl -s http://repo.yundasys.com/shell/nvme/nvme_status.sh|bash

# 日志输出到文件   错误重定向到 标准输出中 注意是追加模式
01 00 * * * /yd/td2/shell/import_job.sh >> /yd/td2/runtime/cron/log.txt 2>&1
# 或者直接丢弃
* * * * * /usr/local/gse/agent/bin/gsectl watch >/dev/null 2>&1
# 但是,如果要分隔文件呢?  下面直接执行就可以,但是,却
/yd/td2/shell/main.sh >> /yd/td2/runtime/cron/log`/usr/bin/date +%Y%m%d%H%M%S`.txt 2>&1

# 如果错误、标准输出,写到不同的文件中,
25 */2 * * * /bin/bash /etc/titanagent/agent_update.sh >> /var/log/titanagent/check.o.log 2>> /var/log/titanagent/check.e.log

脚本示例

#!/bin/bash
# 2021年8月10日  脚本导入任务
# 01 00 * * * /path/to/myshell.sh >> /path/to/log.txt 2>&1
BASEDIR=$(cd `dirname $0`;pwd)
cd $BASEDIR
source /root/.bash_profile
export PATH=/usr/local/bin/:/usr/local/greenplum-db/bin/:$PATH

logmsg(){
    echo "`date '+%Y-%m-%d %H:%M:%S'` $1" 
}

定时脚本启动的不同

定时脚本,在执行的时候,并不会加载一些环境变量的脚本。查阅下面文章。

img

https://blog.csdn.net/gaojing2240/article/details/103908656

定时格式

分 时 日 月 周

# 每分钟执行一次
* * * * *
# 每半小时执行一次
*/30 * * * *
# 周末中午12点执行
0 12 * * 6,7
# 工作日,凌晨两点执行
0 2 * * 1-5
# 两点到4点,12点到16点的整点执行一次
0 2-4,12-16 * * *

符号说明

/ ,表示每,设置步长。

-,表示范围,能与,联合使用。

,,多个值或范围用逗号分隔。

以分钟为示例,复杂的组合如下:

*/3,4,5,8,50-59

FeHelper的定时工具,用来调试还不错。

crontab -e

使用crontab -e的方式,来编辑定时任务。不同的用户,对应的不同的定时任务。运行任务时,以该用户的角色、权限来运行脚本。

关于权限与安全,比如,以root方式运行/mytest.sh,假入该脚本权限为0777,那么普通用户通过修改该脚本,添加特殊指令,并等待定期以root触发,然后很可能权限会泄漏。

关于环境变量,很有脚本运行的时候,会缺少相关的环境变量。另外,最好先cd到执行的目录中。

示例:

# 先cd到脚本文件目录,然后使用php的全路径来运行脚本,虽然环境变量中有php的路径
# 但是,crontab运行时,缺找不到。
0 9 * * 1 cd /yd/td2/shell && /usr/local/bin/php diskstatus.php

要不要先cd到目录中,再执行,这个要看,php文件,如果它中使用相对文件路径引用其他文件,所以,最好先cd到目录中。

环境变量,可能shell中运行缺时找不到。

之前遇到的一个问题是:hexo博客,也是环境变量上中不到相关的程序。

# 用alias解决
alias php='/usr/local/bin/php'

# 使用变量的方式
phpbin='/usr/local/bin/php'
$phpbin test.php

# 环境变量PATH 自己增加
PATH

crontab -l

查看已有哪些定时任务。

配置

在我的ubuntu上看到定时任务上面有如下配置,可以作为脚本运行时的配置参考。如下:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/tmp

其他

定时任务存放的地方(centos):

/var/spool/cron/root

貌似,也可以直接通过修改该文件,来增加定时任务。

日志

所有用户的日志都在这个里面,如果脚本无法执行,可以查看该文件,确定无法执行的原因。但是,需要root权限。

/var/log/cron
ls /var/log/cron*

邮件

当crond执行任务失败时会给用户发一封邮件。(如何开启?),可能有详细的失败日志。

vi /var/spool/mail/root

日志文件重定向

0 6 * * * $HOME/for_crontab/myshell.sh >> $HOME/for_crontab/mylog.log 2>&1

原因排查

首先,先将原来定时任务执行频率调整更低,如* * * * *,然后调试。

执行执行定时任务的脚本,看是否能执行。(能执行,而定时任务下不能执行,可能是某些环境变量缺失。如,简写的php命令不识别。)

查看错误日志。找到原因描述。

错误示例

定时任务:

*/30 * * * * /path/to/hexo_blog.sh >  /path/to/hexo.log 2>&1

错误的代码

alias node="/usr/local/node/bin/node"
alias hexo="/usr/local/node/bin/hexo"
cd /home/nodejs/blog/source/_posts/
refresh(){
    git checkout master
    git branch -D md
    git pull
    git checkout md
    git pull
    git merge master --no-edit
    cd ../..
    echo "$(date)" >> log.txt
    hexo g
}

refresh

修改后的代码:

主要增加了脚本的类型,然后增加了环境变量,貌似node中调用的其他命令依赖了环境变量PATH。

#!/bin/bash
export PATH=/usr/local/bin:/usr/local/node/bin:$PATH
echo $PATH
alias node="/usr/local/node/bin/node"
alias hexo="/usr/local/node/bin/hexo"
cd /home/nodejs/blog/source/_posts/
refresh(){
    git checkout master
    git branch -D md
    git pull
    git checkout md
    git pull
    git merge master --no-edit
    cd ../..
    echo "$(date)" >> log.txt
    hexo g
}

refresh