吐槽 crontab

干嘛写这玩意呢。。。因为这玩意坑不少。

作为 linux 的计划任务程序,使用方法大家都很清楚:

1
crontab -e

然后会用不知道什么程序打开 cron 的配置文件。对我没用错词汇,就是不知道什么程序,我见过用 vim 的、用 nano 的、用一个不知道叫啥名字但快捷键很像 tmux 的(可能是 emcas?),有的系统第一次用 crontab 的时候会让你选用哪种编辑器,但有的完全不会。。。

然后敲命令进去

1
* * * * * [command]

那几个星号:

1
2
3
4
5
6
7
8
*    *    *    *    *
- - - - -
| | | | |
| | | | +----- 星期中星期几 (0 - 7) (星期天 为0)
| | | +---------- 月份 (1 - 12)
| | +--------------- 一个月中的第几天 (1 - 31)
| +-------------------- 小时 (0 - 23)
+------------------------- 分钟 (0 - 59)

另外可以用 */n 这种格式,表示时间刻度内执行 n 次。* 既可以填入单个数字表示某一时间,也可以填入类似 1-9 这种形式,表示时间段。

坑来了:后面的命令,有几个值得注意的地方:

  1. 运行时涉及的所有文件和命令需要绝对路径。

    比如用于 hostloc 一键签到的 php 脚本:

    1
    php loc.php

    在 crontab 中就得这么写:

    1
    0 1 * * * /usr/bin/php /root/loc.php >>/var/log/hostloc.log

    还有 service 之类的命令,得找到 service 的绝对路径:

    1
    which service

    然后类似这么写:

    1
    0 1 * * * /usr/sbin/service xxx restart
  2. “命令里面夹命令”,需要用 ` 号替换括号;如果命令里面有 % 号,需要在前面用 \ 转义。

    比如:

    1
    0 0 1 * * /root/traffic.sh > /root/$(date +%y%m%d).txt&&/root/traffic.sh reset

    就需要改成

    1
    0 0 1 * * /root/traffic.sh > /root/`date "+\%y\%m\%d"`.txt&&/root/traffic.sh reset
  3. 如果运行出错,crontab 不会主动报错,你可以查看一下 crontab 的 service 日志(参考cron - Where is my logfile of crontab? - Unix & Linux Stack Exchange):

    1
    2
    3
    4
    journalctl -u cron.service
    #或者用下面两个
    #journalctl _COMM=cron
    #journalctl _COMM=cron --since="date" --until="date"

    或者查看它本身导出的日志文件(不同的 linux 发行版路径可能不一样,以下这个适用于 debian):

    1
    cat /var/log/syslog

    但这样看到的错误日志其实不够详细。仔细观察的话,出错的日志后面有这么一条:

    1
    (CRON) info (No MTA installed, discarding output)

    意思是 cron 想把错误发到系统内的邮件管理器,但你没装。

    那就装一个好了:

    1
    2
    apt install postfix
    service postfix start

    后续出错的时候就可以通过

    1
    cat /var/spool/mail/root

    查看错误的详细情况。