日期:2014-05-16  浏览次数:20842 次

Crontab和Linux日期相关的tips
好久没有在Javaeye上写东西了,今天碰到一个Linux下schedule任务的问题,记录一下。

crontab分系统级和用户级,系统级的crontab配置文件在/etc/crontab,crontab预定义的定时任务类别分别有:
/etc/crontab.hourly,
/etc/crontab.daily,
/etc/crontab.weekly,
/etc/crontab.monthly,
/etc/crontab.yearly(or crontab.annually),
/etc/crontab.reboot

/etc/crontab文件定义了crontab运行时系统变量,和已启用的定时任务:

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

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly


crontab定时器的命名规则如下:

#  .---------------- 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
#  |   |   |   |  |
#  *   *   *   *  *  command to be executed

Note: 利用/可以定义repeatable任务,如将值“*/2”赋给minute位置,则会每两分钟执行一次。

今天碰到的问题来了:
我要跑一个脚本,脚本日志加上时间戳之后就重定向到日志文件了,所以crontab command就如下:
/home/ec2-user/upload.sh 2>&1 | while read line; do printf "$(date '+%F %T %z')\t$line\n"; done >>/home/ec2-user/upload.log 2>&1

但是当我把crontab任务创建好溜达一圈回来发现收到很多root用户发来的mail:
引用

From: root@ip-10-122-246-207.ec2.internal (Cron Daemon)
To: ec2-user@ip-10-122-246-207.ec2.internal
Subject: Cron <ec2-user@ip-10-122-246-207> /home/ec2-user/upload.sh 2>&1 | while read line; do printf "$(date -u '+
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/ec2-user>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=ec2-user>
X-Cron-Env: <USER=ec2-user>
Status: RO

/bin/sh: -c: line 0: unexpected EOF while looking for matching `''
/bin/sh: -c: line 1: syntax error: unexpected end of file

这个mail很是让人不解,开始以为crontab的任务命令有长度限制,经过一番折腾和搜索crontab官方文档,却发现如下解释:
引用

A <percent-sign> character in this field shall be translated to a <newline>. Any character preceded by a <backslash> (including the '%' ) shall cause that character to be treated literally. Only the first line (up to a '%' or end-of-line) of the command field shall be executed by the command interpreter. The other lines shall be made available to the command as standard input.

原来字符%是一个可被crontab识别的换行符,如此一来%之前的命令才会被执行到,而%之后(第二行)则属于第一行命令的输入参数。这才解释了上述问题。随改之。

改之但是还是得需要日志行加入timestamp,自定义的日期格式是不能用了(包含字符%),故查看date的spec,可以用预定义的几种日期个是进行替换,
比如date -R会采用RFC 2822日期格式进行输出: Fri, 26 Nov 2010 14:31:33 +0000
而date --iso-8601='minutes'则会采用iso-8601日期格式(精确到分钟)来输出: 2010-11-26T14:33+0000

总结一下:Linux下的各种命令/机制必须得一个一个去钻研才能找到突破口,哪怕只是一点很容易被忽略的细节。