cron的使用(二)

来源:互联网 发布:数控车g73怎么编程圆球 编辑:程序博客网 时间:2024/04/28 19:48

了解 cron 概念

  cron 守护进程是一个由实用程序和配置文件组成的小型子系统,在几乎所有类 UNIX 系统上都可以找到某种风格的 cron。cron的组件包括守护进程本身;一组系统范围的配置文件;一组针对特定用户的配置文件;一个用来添加、修改和删除用户配置文件的实用程序;以及一个简单的访问控制设施。一般来说,cron 配置文件或 cron 作业的列表被称为 crontab 或 cron 时间表。

  守护进程 cron 连续运行,每分钟检查一次配置文件中的修改。cron 读取系统范围的和针对用户的crontab(分别在下面两段中详细说明)、相应地更新事件调度计划并执行这一分钟内应该执行的所有命令。这个守护进程还捕捉每个作业的输出(如果有输出的话),并把结果通过电子邮件发送给作业的所有者。

  可以在三个位置定义与系统相关的 作业:/etc/crontab、/etc/cron.d 中的任何文件以及特殊目录/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly 和 /etc/cron.monthly:

  主要的系统 crontab 是/etc/crontab。这个文件有独特的语法(在下一节中讨论),其中定义的每个作业根据它自己的时间表(比如每小时两次或每天一次)作为指定的用户运行。使用 /etc/crontab 调度各种管理和维护任务。

  还可以在 /etc/cron.d 目录中维护一组 crontab。通过创建crontab,按照逻辑对属于某一子系统的命令进行分组。例如,PHP 5 编程语言的包在 /etc/cron.d 中安装一个名为 php5 的crontab,它会定期清除不使用的会话。/etc/cron.d 中的文件采用与 /etc/crontab相同的语法,每个作业按照自己的时间表并作为特定的用户运行。

  还可以把 shell 脚本直接放在/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly 或 /etc/cron.monthly目录中,这样就可以每小时、每天、每周或每月运行此脚本一次。放在这里的脚本作为超级用户运行。

  针对用户的 crontab 集合通常放在 /var/spool/cron/crontabs 中。(具体位置请参见您的 UNIX系统文档。一些系统把用户 crontab 放在 /usr/lib 中)。但是,不能直接编辑此目录中的文件,而是使用 crontab实用程序创建 crontab 并提交文件。稍后讨论如何管理个人的 crontab。

  最后,可以分别使用访问控制文件 /etc/cron.allow 和 /etc/cron.deny 允许或拒绝用户访问 cron。例如,如果某个用户的作业可能会破坏系统的正常操作,就可以拒绝他访问 cron。

  如您所见,不需要为保持系统不间断运行而牺牲您的休息时间。只需确定作业、定义它的调度计划并在适当的 crontab 中设置此作业,然后就可以放心地休息了。现在就来看看 cron 文件的特殊语法。

  处理 crontab

  crontab 仅仅是一个文本文件,可以用任何 UNIX 编辑器编辑它。它可以包含四种代码行:空行、注释、环境变量设置和命令。

  空行和注释

  文件中的空行和多余的空格被忽略。空行和空格有助于提高 crontab 的可读性,使 crontab 组织有序。

  还可以使用注释对每个作业的时间表和用途加以说明。要想创建注释,只需在一行的开头加上一个井号(#)。

  环境变量和命令

  cron 最终使用一个 shell 执行每个命令。可以通过环境变量修改或定制 shell 的行为。

  在 crontab 中很容易设置 shell 环境变量。只需输入 VARIABLE=value,把 VARIABLE 替换为变量名,把 value 替换为一个值。例如,crontab 行:

PATH=/usr/bin:/bin:/usr/local/bin

  指定一个有序的目录列表作为 shell 搜索路径。

  cron 预定义了五个环境变量:

  PATH 的默认值是 /usr/bin:/bin。

  SHELL 预设置为 /bin/sh。

  LOGNAME 初始化为 crontab 所有者的用户名。

  HOME 设置为 crontab 所有者的主目录,比如 /home/joe。

  MAILTO 设置为 crontab 所有者的名称。

  要想修改这些默认值或设置任何变量,只需在 crontab 中设置适当的环境变量。

  当然,crontab 可以包含任意数量的命令行。每个命令行指定一个频率、一个用户名(只对于系统 crontab)和一个要运行的任务。例如,命令:

5 0 * * *  root  find /tmp -type f -empty -delete

  在每天 12:05 a.m(5 0 * * *)删除 /tmp 中的所有空文件和目录(find /tmp -type f -empty -delete)。此作业作为根用户(root)运行。

  系统 crontab 命令必须指定一个用户名,作为运行此任务所用的用户。(因此,在 /etc/crontab中可能看到上面的命令)。针对用户的 crontab 不能指定用户名;一个用户的 cron 命令总是作为这个用户运行。是否有用户名是系统crontab 和用户 crontab 之间的惟一差异。

  下面讨论定制时间表的众多方式。

  定制时间表

  cron 时间表允许以多种方式运行作业,比如每分钟或在特定日期的特定时间。调度的参数非常灵活。

  cron 字段

  可以通过五个字段调整频率:分、小时、月中日、月份和周中的日期(如周一,周二)。表 1 总结如何调整每个字段。

  表 1. cron 作业的调度选项

 

位置字段值说明1分0-59 2小时0-23 3月中日1-31与分和小时不同,月中日不是从零开始的。4月份1-12月份也不是从零开始的。也可以不使用 1-12 的数字,而是使用月份名的前三个字母,比如 jan 或 may。 5周中日0-70 和 7 都代表星期日。还可以使用名称的前三个字母,比如 mon 或 wed。

  除了名称或数字之外,还可以使用星号(*)表示 “所有”。例如,在分钟位置上的星号表示这一天中的每一分钟。(在某些情况下确实需要如此高的频率,但是一定要小心,以这种频率执行的任务应该非常简单,不会长时间运行)。

  还可以使用值的列表、范围和步长(增量)分别指定多个值、连续的值范围和不连续的值范围。甚至可以组合使用列表和范围。列表 是一个逗号分隔的值集。范围 由启始值和结束值(含)以及可选的步长值构成。

  我们来看一些示例。表 2 中的每一行包含一个时间表及其说明。当分、小时和日期字段与当前时间匹配时,cron 会执行命令;如果月中日和周中日受到限制(也就是说,不是 *),那么当这两个字段中至少一个 与当前时间匹配时,cron 也会执行命令。

  表 2. cron 作业的时间表示例

 

调度计划 分小时月中日月份周中日期说明01151,3,5,7,9,11*在 1、3、5、7、9 和 11 月的 15 日的 1 a.m. 运行命令。为了更容易理解,也可以把这个时间表写成 0 1 15 jan,mar,may,jul,sep,nov *。在指定列表时,不要在逗号后面加空格。 0-59/15****这个调度计划每 15 分钟运行命令一次。 30***wed,fri这个时间表只在星期三和星期五每小时的 30 分时执行命令一次。(在列表中可以使用日和月份的名称,但是在范围中不可以)。 0,300-5,17-23***在午夜到 5 a.m. 以及 7 p.m. 到 11 p.m. 之间整点时和 30 分时运行命令。 0011*在每年 1 月 1 日午夜执行命令一次。00**0在每个星期日午夜运行命令。这相当于每周一次。 30010,20,30*6因为月中日和周中日受到限制,这个时间表在每星期六和每月的 10、20 和 30 日(二月除外)的 12:30 a.m. 运行命令。

  如您所见,实际上可以使用这五个参数指定任何调度计划。为了更加简便,Vixie cron 还提供了常用调度计划的简写形式。表 3 列出一些简写形式。

  表 3. 常用调度计划的简写形式

 

简写形式说明@reboot每当计算机重新引导时运行命令。@daily每天一次的简写形式。@weekly每周一次的简写形式。@annually每年一次的简写形式。也可以写成 @yearly。 @midnight在每天午夜运行命令。这个简写形式相当于 @daily。

  如果喜欢使用简写形式,只需用它们替代 cron 命令的前五个字段。下面这个命令看起来简单多了。

@daily root /usr/local/scripts/clean_old_files.sh

  crontab 命令示例

  掌握了基本概念之后,我们来看一些用户 crontab 命令示例。同样的命令也可以应用系统范围:只需在所有系统 crontab 项中周中日字段(第五个字段)后面指定一个用户名。

  创建个人 crontab

  要想创建个人 crontab,可以用任何文本编辑器创建一个文件。按照惯例,个人 crontab 文件保存在 ~/.crontab 中,但是可以使用任何文件名。

PATH=/usr/bin:/bin:/usr/local/bin
#
# Every day, print and delete all temporary files whose names begin with '.#'
@daily   find $HOME -type f -name '.#*' -print -delete
  
#
# Every week, show me what is consuming space in my home directory
@weekly   du -sh $HOME

  通过 crontab 实用程序提交个人 crontab

  在编辑文件(比如 ~/mycrontab)之后,通过 crontab 实用程序把它提交给 cron:

% crontab ~/mycrontab

  查看 cron 中存储的信息

  要想查看 cron 中存储的信息,可以输入 crontab -l:

% crontab -l
PATH=/usr/bin:/bin:/usr/local/bin
  
#
# Every day, print and delete all temporary files whose names begin with '.#'
@daily   find $HOME -type f -name '.#*' -print -delete
#
# Every week, show me what is consuming space in my home directory
@weekly   du -sh $HOME

  替换 crontab

  在任何时候,都可以使用 crontab 实用程序替换您的 crontab。只需提交一个新文件或同一文件的修订版。要想删除 crontab 作业,只需输入 crontab -r:

% whoami
joe
% crontab ~/mycrontab
% crontab -l
PATH=/usr/bin:/bin:/usr/local/bin
...
% crontab -r
% crontab -l
crontab: no crontab for joe

  替代 cron 的机制

  尽管 cron 确实很有用,但是您还应该了解可以替代它的两种机制。

  anacron

  如果系统常常关机或进入休眠状态(例如,如果使用 UNIX 笔记本计算机的话),那么可以考虑在系统中添加anacron。anacron 与 cron 的相似之处在于,它也把作业安排在以后运行;但是,与 cron不同,即使作业的预定运行时间已经过了,anacron 也会运行作业。

  例如,如果安排在星期六运行文件系统备份,但是系统在星期五到星期一关机了,那么当系统在星期一重新启动时,anacron 会立即运行星期六的作业。与之相反,cron 仅仅检查现在是否应该运行作业;因此,如果在作业的预定运行时间系统是关闭的,就不运行作业。

  anacron 的调度选项比 cron 少得多。它只能以整天的时间间隔调度作业,比如一天、7 天或 30 天;但是对于那些必须频繁且可靠地运行的作业,它是更好的选择。

  另外,必须从 cron 启动 anacron。每当 anacron运行时,它读取自己的配置文件。配置文件包含由作业及其频率(用天数表示)组成的配置对。如果作业在预定的时间没有运行,anacron就运行此作业并记录运行作业的时间。运行完所有作业之后,anacron 退出。

  在大多数 Linux 发行版上都可以找到 anacron,但是也很容易自己下载并构建源代码。访问 anacron 项目页面 获得最新版本。

  anacron 的主要配置文件可以在 /etc/anacron 中找到。可以像配置 cron 时那样设置环境变量,但是更简单:

SHELL=/bin/zsh
PATH=/usr/bin:/bin:/usr/local/bin
# format: frequency delay name job
1 10 day-to-day daily.chores.sh

  第一个数字是周期,所以 1 表示每天运行一次,7 表示每 7 天运行一次,等等。第二个数字是延迟,也就是从 anacron启动之后到执行这个作业之间等待的分钟数。如果把延迟字段设置为不同的值,就可以防止所有作业同时启动。名称 day-to-day只是一个有帮助的昵称。配置行的其余部分指定作业;在这里,每天运行在指定路径中找到的 shell 脚本 daily.chores.sh 一次。

  anacron 以手册页形式提供了出色的文档,还可以在网上找到关于 anacron 的提示。(请阅读我在 2007 年 10月编辑的 Rod Smith 撰写的 Linux Magazine 文章)。anacron 适合 UNIX爱好者和需要额外保障的系统管理员使用。

  launchd:cron 的现代替代机制

  cron 确实是一种功能强大、值得信赖的实用程序,它的广泛流行就证明了这一点。Vixie cron 最近又有所改进,比如增加了简写方式 @reboot,进一步简化了管理。但是,cron 仍然有一些缺点:

  尽管可以在 crontab 文件中定义 cron 作业,但是不能从命令行启动和停止 cron 作业。另外,不能在命令行上创建专用作业并提交给日历。

  cron 不实施资源限制。如果作业作为根用户运行,就能够消耗无数的处理器时间和内存。在实践中,可能希望限制一个作业,以免它影响其他 cron 作业和系统操作的总体质量。

  cron 作业严格地与一个调度计划相关联。例如,无法只在发生某一事件(比如创建一个文件)时启动作业。

  从更大的范畴来看,类 UNIX 系统的许多核心组件都能够根据需要启动其他程序,包括 cron、用于网络守护进程的 xinetd(或inetd)和 init(所有系统进程的起源)。每个核心组件都有自己的配置文件,所以很难知道哪个组件最适合完成某个修改。

  为了克服这些缺点,Apple Computer 开发了一个统一的启动工具launchd,它可以在引导时、根据需要和按照指定的时间间隔启动进程。实际上,在 Mac OS 10.4 Tiger 中 launchd已经替代了 cron(和 init 以及用来引导和初始化系统的其他几个系统实用程序)。(Apple 在系统上保留了cron,以便为用户提供方便,而且 Vixie cron 的调度选项更灵活)。Mac OS X 的引导速度很快确实可以归功于launchd:它会在引导时列出要启动的程序,但是只在首次需要时执行程序。

  launchd 是开放源码的,可以从 Mac OS Forge 上它的主页获得源代码。目前,launchd 已经被移植到FreeBSD 上,但是还没有移植到其他 UNIX 或 Linux 系统。但是,许多项目正在积极地实现与 launchd等效的程序,所以简要地了解它的特性是有必要的:

  launchd并不创建作业来检查目录中是否有新文件,而是自动监视目录中是否有新文件或者监视空目录中是否添加了任何文件,并根据需要启动作业。launchd不执行轮询;而是使用 kqueues 设施让内核在目录发生变化时通知它。(Linux 具有一种相似的事件设施 inotify,以后的一篇developerWorks 文章将讨论它) 。

  如果指定了,launchd 会使用 chroot 把您的作业发送到一个新目录。chroot 读作“cha-root”,它是一个系统调用,可以改变前向斜杠(/)和根目录指向的目录。因此,如果使用 chroot 把文件发送到/opt/root,/opt/root 之外的所有文件就是不可访问的(毕竟,/opt/root 现在是/,也就是文件系统的顶级目录),/opt/root 中的所有目录成为一级目录。通常使用 chroot限制作业,使代码无法进入更大的文件系统,以避免产生损害。

  可以为作业设置资源限制。可以限制的资源包括内存、堆栈大小和打开的文件的最大数量。

  当定义一个任务并把它装载到 launchd 中之后,可以按照名称从命令行启动和停止作业。

  launchd 由三个组件组成:launchd 守护进程本身;用来添加、修改和删除作业以及控制 launchd 的launchctl 实用程序;一个或多个配置文件,每个文件定义一个或多个作业。由于它起源于 Mac OS X,launchd配置文件只是简单的属性文件,可以用 Extensible Markup Language (XML) 表示。

  简单地说,在 Mac OS X 上使用 launchd 的步骤如下(要监视一个目录中添加的文件并根据需要运行作业):

  创建一个属性文件来表达此作业及其所有属性。

  可以使用 Mac 的 Property Editor,也可以手工编辑 XML。无论采用哪种方法,产生的文件都应该与 清单 1 相似。

  清单 1. 监视文件系统目录变化的 launchd 作业示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST
      1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.example.processor</string>
  <key>OnDemand</key>
  <true/>
  <key>Program</key>
  <string>/Users/strike/bin/processor</string>
  <key>ProgramArguments</key>
  <array>
    <string>processor</string>
  </array>
  <key>WatchPaths</key>
  <array>
    <string>/Users/strike/data/incoming</string>
  </array>
</dict>
</plist>

  简单地说,当 /Users/strike/data/incoming 目录的内容发生变化时,此文件运行/Users/strike/bin/processor 中的实用程序脚本。把 OnDemand 设置为 True 让 launchd根据需要启动此作业。把此文件保存到 ~/Library/LaunchAgents/com.example.processor.plist。

  用 launchctl 把此作业装载到 launchd 中:% launchctl load ~/Library/LaunchAgents/com.example.processor.plist

  如果希望检查最近的操作或查看保存的作业的列表,只需输入 launchctl list。

  要想删除作业,只需带 unload 选项使用 launchctl:% launchctl unload -w ~/Library/LaunchAgents/com.example.processor.plist

  -w 的作用是什么?它完全删除 launchd 中的作业。如果没有这个选项,作业会在登录时自动地重新装载(因为作业还在启动代理的用户集合中)。

  launchd 手册页包含大量信息;如果您是 Mac OS X 用户,还可以找到大量针对 launchd 的应用程序。一些聪明的开发人员正在把 launchd 迁移到更广泛的平台。

  使用 cron 让工作更轻松

  学习关于使用 cron 的一些提示和技巧,了解这个守护进程和相似的其他程序为什么是您的好朋友。

  提示和技巧

  下面是关于 cron 的一些提示、技巧和常见的问题:

  与在终端窗口中使用的 shell 或 shell 脚本不同,cron 并不 在 crontab 文件中就地展开环境变量。换句话说,如果在 crontab 中输入:HOME=/home/joe
PATH=$HOME/bin:/usr/bin:/bin

  那么 PATH 并不会设置为您期望的路径。您必须手工展开所有变量,比如:

HOME=/home/joe
PATH=/home/joe/bin:/usr/bin:/bin

  但是,因为每个 cron 命令都由 shell 执行,所以命令可以 引用变量名。例如,如果在个人 crontab 中编写以下命令(注意这一行中省略了用户名参数):

@daily $HOME/bin/cleanup_daily.sh

  那么 $HOME 会正确地展开。

  不要把计算密集型任务安排在同一时间启动,比如 @midnight。如果可能的话,在凌晨的几小时中分散地启动这些任务,以避免它们争用资源。

  正如上面提到的,在默认情况下环境变量 SHELL 设置为 /bin/sh。如果不修改此变量,crontab 中的所有命令都由/bin/sh 解释。但是,如果您不熟悉 /bin/sh,更喜欢另一种 shell,那么可以设置 SHELL 并使用这种 shell的命令语法。

  例如,如果设置 SHELL=/bin/zsh,那么所有命令都可以使用 Z shell 的功能,比如它的高级重定向操作符:

SHELL=/bin/zsh
@daily uptime > daily >> weekly

  在这里,uptime 命令的输出覆盖 daily 文件(>daily)并追加到 weekly 文件中(>> weekly)。

  使用访问控制列表 (ACL) — /etc/cron.allow 和 /etc/cron.deny — 允许或拒绝特定用户运行cron 作业。如果希望把对 cron 的访问权限制在很少几个用户,那么在 /etc/cron.allow中列出这些用户的用户名。未指定的任何用户都无法使用 crontab 实用程序提交 crontab。但是,如果希望允许大多数人访问 cron而拒绝少数用户,那么在 /etc/cron.deny 中列出受到限制的用户。

  例如,如果 /etc/cron.allow 的内容如下:

joe
zelda

  那么除 Joe 和 Zelda 之外任何用户都无法访问 cron:

% whoami
strike
% crontab ~/.crontab
You (strike) are not allowed to use this program (crontab)
See crontab(1) for more information

  要想禁用 cron 发出的电子邮件报告,应该在 crontab 中设置 MAILTO=""。

  再次重申,不要在列表中使用空格。列表值以逗号分隔。在 Vixie cron 中,在范围中不使用日和月份的名称。

  要仔细阅读系统的 cron 文档。路径、特性和简便措施都可能不一样。在命令行上输入 man 5 crontab 了解 crontab文件的语法。输入 man 1 crontab 了解 crontab 实用程序。在命令行上输入 man cron 或 man 8 cron 了解cron 守护进程本身的选项。

  系统管理员最好的朋友

  cron 和与它相似的程序对于系统管理员非常有帮助。如果您需要反复执行相同任务,就可以考虑用 cron 实现自动化。捕捉具有许多步骤的复杂任务常常需要 shell 脚本,但是许多任务只需要一行命令。

  下面仅仅是一些思路:

  通过组合使用 cron 和数据库工具,创建每日转储。例如,命令:@daily joe mysqldump -pjoespwd accounts > $HOME/backups/accounts.`date +%F`.sql

  每天把数据库 accounts 转储到一个文件。嵌入的日期命令(`date +%F`)确保文件名是惟一的,比如accounts.2008-08-07.sql。此命令作为用户 joe 运行,所以用 -p 指定 Joe 的密码。此命令还可以放在 Joe自己的 crontab 中,因为转储需要他的 MySQL 凭证。

  locate 子系统为系统上的所有文件编制索引,并把每个文件的完整路径存储在数据库中。然后,从命令行查询此数据库,就可以立即找到文件。当然,可以根据需要用 find 搜索文件,但是必须等待它搜索文件系统,这可能很慢。

  为了让定位子系统发挥作用,必须定期为文件系统编制索引,因为随时可能添加和删除文件。这种情况就非常适合使用 cron。

0 0,12 * * * root updatedb

  这个 crontab 项每天运行 updatedb(locate 更新实用程序)两次。

  显然很适合用 cron 实现自动化的另一个任务是,把文件从主服务器复制到众多的从服务器。rsync 是一种跨多个系统分布和同步文件集合的现代实用程序。许多网管都通过组合使用 cron 和 rsync 把网站的主拷贝复制到服务器群中的每台服务器。@midnight www rsync -avz /var/www/site slave1:/var/www

  在每天午夜,rsync 都会把 /var/www/site 复制(-avz)到 slave1 上的 /var/www。

  使用命令行实用程序 mail 和 shell 管道操作符(|)把任务的输出发送给团队中的一个或多个成员。

@weekly root df --print-type --local -h |& mail -s "Weekly df report" andy bob

  在这里,每周通过电子邮件把 df 的输出发送给用户 Andy 和 Bob,让他们能够监视磁盘使用量。

  结束语

  教程结束语

  无论您是单独使用 UNIX系统,还是管理有数百位用户的系统,自动执行维护任务都有助于节省时间、减少错误以及保持机器不间断运行。cron 是在 UNIX系统上实现自动化的关键组件,只需发挥一点儿想像力,就可以让计算机为您工作,而不是由您 “伺候” 计算机。

  cron 有助于更轻松地完成工作。现在,您可以睡个好觉了。

原创粉丝点击