python 应用crontab 定时器

转载 2012年03月23日 06:11:44

在实现一个功能的时候需要定时调用,感觉linux 自带的定时器不错,但是需要通过python语言 控制定时任务的启动删除,添加和修改。

在网上找到一个开源的 crontab.py, 这个文件对 crontab 实现了封装,直接调用这个文件写的函数就可以。

crontab.py:


#
# Copyright 2010, Martin Owens.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Rewritten from scratch, but based on the code from gnome-schedual by:
# - Philip Van Hoof <me at pvanhoof dot be>
# - Gaute Hope <eg at gaute dot vetsj dot com>
# - Kristof Vansant <de_lupus at pandora dot be>
#
"""
Example Use:


from crontab import CronTab


tab = CronTab()
cron = tab.new(command='/usr/bin/echo')


cron.minute().during(5,50).every(5)
cron.hour().every(4)


cron2 = tab.new(command='/foo/bar',comment='SomeID')
cron2.every_reboot()


list = tab.find_command('bar')
cron3 = list[0]
cron3.clear()
cron3.minute().every(1)


print unicode(tab.render())


for cron4 in tab.find_command('echo'):
    print cron4


for cron5 in tab:
    print cron5


tab.remove_all('echo')


t.write()
"""


import os, re, sys
import tempfile


__version__ = '0.9.5'


CRONCMD = "/usr/bin/crontab"
ITEMREX = re.compile('^\s*([^@#\s]+)\s+([^@#\s]+)\s+([^@#\s]+)' +
    '\s+([^@#\s]+)\s+([^@#\s]+)\s+([^#\n]*)(\s+#\s*([^\n]*)|$)')
SPECREX = re.compile('@(\w+)\s([^#\n]*)(\s+#\s*([^\n]*)|$)')
DEVNULL = ">/dev/null 2>&1"


MONTH_ENUM = [
    'jan', 'feb', 'mar', 'apr', 'may',
    'jun', 'jul', 'aug', 'sep', 'oct',
    'nov', 'dec',
]
WEEK_ENUM  = [
    'sun', 'mon', 'tue', 'wed', 'thu',
    'fri', 'sat', 'sun',
]


SPECIALS = {
    "reboot"  : '@reboot',
    "hourly"  : '0 * * * *',
    "daily"   : '0 0 * * *',
    "weekly"  : '0 0 * * 0',
    "monthly" : '0 0 1 * *',
    "yearly"  : '0 0 1 1 *',
    "annually": '0 0 1 1 *',
    "midnight": '0 0 * * *'
}


S_INFO = [
    { 'name' : 'Minutes',      'max_v' : 59, 'min_v' : 0 },
    { 'name' : 'Hours',        'max_v' : 23, 'min_v' : 0 },
    { 'name' : 'Day of Month', 'max_v' : 31, 'min_v' : 1 },
    { 'name' : 'Month',        'max_v' : 12, 'min_v' : 1, 'enum' : MONTH_ENUM },
    { 'name' : 'Day of Week',  'max_v' : 7,  'min_v' : 0, 'enum' : WEEK_ENUM },
]


class CronTab(object):
    """
    Crontab object which can access any time based cron using the standard.


    user = Set the user of the crontab (defaults to $USER)
    fake_tab = Don't set to crontab at all, set to testable fake tab variable.
    """
    def __init__(self, user=None, fake_tab=None):
        self.user  = user
        self.root  = ( os.getuid() == 0 )
        self.lines = None
        self.crons = None
        self.fake = fake_tab
        self.read()


    def read(self):
        """
        Read in the crontab from the system into the object, called
        automatically when listing or using the object. use for refresh.
        """
        self.crons = []
        self.lines = []
        if self.fake:
          lines = self.fake.split('\n')
        else:
          lines = os.popen(self._read_execute()).readlines()
        for line in lines:
            cron = CronItem(line)
            if cron.is_valid():
                self.crons.append(cron)
                self.lines.append(cron)
            else:
                self.lines.append(line.replace('\n',''))


    def write(self):
        """Write the crontab to the system. Saves all information."""
        # Add to either the crontab or the fake tab.
        if self.fake != None:
          self.fake = self.render()
          return


        filed, path = tempfile.mkstemp()
        fileh = os.fdopen(filed, 'w')
        #fileh.write(self.render())
        fileh.write("\n".join(filter(lambda x: not x.lstrip().startswith('#'), self.render().split("\n"))))
        fileh.close()
        # Add the entire crontab back to the user crontab
        os.system(self._write_execute(path))
        os.unlink(path)


    def render(self):
        """Render this crontab as it would be in the crontab."""
        crons = []
        for cron in self.lines:
            if type(cron) == CronItem and not cron.is_valid():
                crons.append("# " + unicode(cron))
                sys.stderr.write(
                    "Ignoring invalid crontab line `%s`\n" % str(cron))
                continue
            crons.append(unicode(cron))
        result = '\n'.join(crons)
        if result[-1] not in [ '\n', '\r' ]:
            result += '\n'
        return result


    def new(self, command='', comment=''):
        """
        Create a new cron with a command and comment.


        Returns the new CronItem object.
        """
        item = CronItem(command=command, meta=comment)
        self.crons.append(item)
        self.lines.append(item)
        return item


    def find_command(self, command):
        """Return a list of crons using a command."""
        result = []
        for cron in self.crons:
            if cron.command.match(command):
                result.append(cron)
        return result


    def remove_all(self, command):
        """Removes all crons using the stated command."""
        l_value = self.find_command(command)
        for c_value in l_value:
            self.remove(c_value)


    def remove(self, item):
        """Remove a selected cron from the crontab."""
        self.crons.remove(item)
        self.lines.remove(item)


    def _read_execute(self):
        """Returns the command line for reading a crontab"""
        return "%s -l%s" % (CRONCMD, self._user_execute())


    def _write_execute(self, path):
        """Return the command line for writing a crontab"""
        return "%s %s%s" % (CRONCMD, path, self._user_execute())


    def _user_execute(self):
        """User command switches to append to the read and write commands."""
        if self.user:
            return ' -u %s' % str(self.user)
        return ''


    def __iter__(self):
        return self.crons.__iter__()


    def __unicode__(self):
        return self.render()




class CronItem(object):
    """
    An item which objectifies a single line of a crontab and
    May be considered to be a cron job object.
    """
    def __init__(self, line=None, command='', meta=''):
        self.valid = False
        self.slices  = []
        self.special = False
        self.set_slices()
        self._meta   = meta
        if line:
            self.parse(line)
        elif command:
            self.command = CronCommand(unicode(command))
            self.valid = True


    def parse(self, line):
        """Parse a cron line string and save the info as the objects."""
        result = ITEMREX.findall(line)
        if result:
            o_value = result[0]
            self.command = CronCommand(o_value[5])
            self._meta   = o_value[7]
            self.set_slices( o_value )
            self.valid = True
        elif line.find('@') < line.find('#') or line.find('#')==-1:
            result = SPECREX.findall(line)
            if result and SPECIALS.has_key(result[0][0]):
                o_value = result[0]
                self.command = CronCommand(o_value[1])
                self._meta   = o_value[3]
                value = SPECIALS[o_value[0]]
                if value.find('@') != -1:
                    self.special = value
                else:
                    self.set_slices( value.split(' ') )
                self.valid = True


    def set_slices(self, o_value=None):
        """Set the values of this slice set"""
        self.slices = []
        for i_value in range(0, 5):
            if not o_value:
                o_value = [None, None, None, None, None]
            self.slices.append(
                CronSlice(value=o_value[i_value], **S_INFO[i_value]))


    def is_valid(self):
        """Return true if this slice set is valid"""
        return self.valid


    def render(self):
        """Render this set slice to a string"""
        time = ''
        if not self.special:
            slices = []
            for i in range(0, 5):
                slices.append(unicode(self.slices[i]))
            time = ' '.join(slices)
        if self.special or time in SPECIALS.values():
            if self.special:
                time = self.special
            else:
                time = "@%s" % SPECIALS.keys()[SPECIALS.values().index(time)]


        result = "%s %s" % (time, unicode(self.command))
        if self.meta():
            result += " # " + self.meta()
        return result




    def meta(self, value=None):
        """Return or set the meta value to replace the set values"""
        if value:
            self._meta = value
        return self._meta


    def every_reboot(self):
        """Set to every reboot instead of a time pattern"""
        self.special = '@reboot'


    def clear(self):
        """Clear the special and set values"""
        self.special = None
        for slice_v in self.slices:
            slice_v.clear()


    def minute(self):
        """Return the minute slice"""
        return self.slices[0]


    def hour(self):
        """Return the hour slice"""
        return self.slices[1]


    def dom(self):
        """Return the day-of-the month slice"""
        return self.slices[2]


    def month(self):
        """Return the month slice"""
        return self.slices[3]


    def dow(self):
        """Return the day of the week slice"""
        return self.slices[4]


    def __str__(self):
        return self.__unicode__()


    def __unicode__(self):
        return self.render()




class CronSlice(object):
    """Cron slice object which shows a time pattern"""
    def __init__(self, name, min_v, max_v, enum=None, value=None):
        self.name  = name
        self.min   = min_v
        self.max   = max_v
        self.enum  = enum
        self.parts = []
        self.value(value)


    def value(self, value=None):
        """Return the value of the entire slice."""
        if value:
            self.parts = []
            for part in value.split(','):
                if part.find("/") > 0 or part.find("-") > 0 or part == '*':
                    self.parts.append( self.get_range( part ) )
                else:
                    if self.enum and part.lower() in self.enum:
                        part = self.enum.index(part.lower())
                    try:
                        self.parts.append( int(part) )
                    except:
                        raise ValueError(
                            'Unknown cron time part for %s: %s' % (
                            self.name, part))
        return self.render()


    def render(self):
        """Return the slice rendered as a crontab"""
        result = []
        for part in self.parts:
            result.append(unicode(part))
        if not result:
            return '*'
        return ','.join(result)


    def __str__(self):
        return self.__unicode__()


    def __unicode__(self):
        return self.render()


    def every(self, n_value):
        """Set the every X units value"""
        self.parts = [ self.get_range( '*/%d' % int(n_value) ) ]


    def on(self, *n_value):
        """Set the on the time value."""
        self.parts += n_value


    def during(self, value_from, value_to):
        """Set the During value, which sets a range"""
        range_value = self.get_range(
            "%s-%s" % (str(value_from), str(value_to)))
        self.parts.append( range_value )
        return range_value


    def clear(self):
        """clear the slice ready for new vaues"""
        self.parts = []


    def get_range(self, range_value):
        """Return a cron range for this slice"""
        return CronRange( self, range_value )




class CronRange(object):
    """A range between one value and another for a time range."""
    def __init__(self, slice_value, range_value=None):
        self.value_from = None
        self.value_to = None
        self.slice = slice_value
        self.seq   = 1
        if not range_value:
            range_value = '*'
        self.parse(range_value)


    def parse(self, value):
        """Parse a ranged value in a cronjob"""
        if value.find('/') > 0:
            value, self.seq = value.split('/')
        if value.find('-') > 0:
            from_val, to_val = value.split('-')
            self.value_from = self.clean_value(from_val)
            self.value_to  = self.clean_value(to_val)
        elif value == '*':
            self.value_from = self.slice.min
            self.value_to  = self.slice.max
        else:
            raise ValueError, 'Unknown cron range value %s' % value


    def render(self):
        """Render the ranged value for a cronjob"""
        value = '*'
        if self.value_from > self.slice.min or self.value_to < self.slice.max:
            value = "%d-%d" % (int(self.value_from), int(self.value_to))
        if int(self.seq) != 1:
            value += "/%d" % (int(self.seq))
        return value


    def clean_value(self, value):
        """Return a cleaned value of the ranged value"""
        if self.slice.enum and str(value).lower() in self.slice.enum:
            value = self.slice.enum.index(str(value).lower())
        try:
            value = int(value)
            if value >= self.slice.min and value <= self.slice.max:
                return value
        except ValueError:
            raise ValueError('Invalid range value %s' % str(value))


    def every(self, value):
        """Set the sequence value for this range."""
        self.seq = int(value)


    def __str__(self):
        return self.__unicode__()


    def __unicode__(self):
        return self.render()




class CronCommand(object):
    """Reprisent a cron command as an object."""
    def __init__(self, line):
        self._command = line


    def match(self, command):
        """Match the command given"""
        if command in self._command:
            return True
        return False


    def command(self):
        """Return the command line"""
        return self._command


    def __str__(self):
        """Return a string as a value"""
        return self.__unicode__()


    def __unicode__(self):
        """Return unicode command line value"""
        return self.command()

调用方法:

   from crontab import CronTab

    tab = CronTab()


    curpath = os.path.dirname(os.path.realpath(__file__))
    curpath = curpath + '/'
    comment = 'create stream:' + streamid + ' program:' + programname
    livetype = 'ism'
    pythoncmd = 'python ' + curpath + 'ProgramRecordStartToctm.py' + ' ' +  streamid + ' ' + programname + ' ' + start_sec + ' ' + livetype + ' ' +  comment
    
    #crontime  = ((int)(start_min)) + 1
    cron = tab.new(command=pythoncmd)
    #cron.minute().value((str)(crontime))
    cron.minute().value(start_min)
    cron.hour().value(start_hour)
    cron.dom().value(start_date)
    cron.month().value(start_month)
    tab.write()


相关文章推荐

python-crontab实现定时任务

用django-crontab实现定时任务: 1.安装django-crontab 2.安装完成后,将‘django-crontab’添加到settings.py中的INSTALL_APP中,...

crontab 定时执行python脚本

今天用python写了处理文件的程序,但是因为快要下班了,所以想用crontab来完成。搜了一下,大部分都是执行的shell脚本,自己根据搜索的资料写了测试了几次,亲测能用,整理一下。 参考网址:h...

解决crontab python执行环境不一致问题

遇到一个坑爹的问题,由于crontab python执行环境与普通用户的不一致,导致crontab 执行python总是提示没有缺少必要的包。 google以后发现,crontab python执...

crontab 定时执行python脚本

今天用python写了处理文件的程序,但是因为快要下班了,所以想用crontab来完成。搜了一下,大部分都是执行的shell脚本,自己根据搜索的资料写了测试了几次,亲测能用,整理一下。 参考网址...

Python脚本在crontab定时任务中无法运行,但是对应脚本手动执行成功

1、问题描述 在用crontab设置定时任务时,发现py脚本在crontab中报错,显示import某些包找不到,但是手动直接运行py脚本,完全正常。 01 05 * * * cd /data/f...

Python定时任务框架APScheduler

APScheduler是基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能,使用起来十分方便。提供了基于日期、固定时间间隔以及crontab类型的任务,并且可以持久化任务。基...

linux 定时任务crontab ,python API

Description Crontab module for read and writing crontab files and accessing the system cron automat...

linux crontab python

因项目需要定时任务,crontab
  • i_bruce
  • i_bruce
  • 2014年11月18日 10:13
  • 1105

Linux中使用python crontab设置定时任务的方法详解

熟悉linux系统的朋友应该知道在linux中可以使用crontab设置定时任务。可以通过命令crontab -e编写任务。当然也可以直接写配置文件设置任务。本文和大家分享的就是使用python ...

Jenkins下邮件通知的设置

首先需要安装Email插件,这里就不详讲这部分工作了,主要介绍下邮件的设置。 A点击系统配置 Manage Jenkins  -- Configure System ,滑动到Extend ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:python 应用crontab 定时器
举报原因:
原因补充:

(最多只允许输入30个字)