Difference between revisions of "Cron (简体中文)"

From ArchWiki
Jump to: navigation, search
m (更新翻译)
(Update translation.)
Line 10: Line 10:
 
{{Related|systemd/Timers}}
 
{{Related|systemd/Timers}}
 
{{Related articles end}}
 
{{Related articles end}}
''cron''是一个在类Unix操作系统上的任务计划程序。它可以让用户在指定时间段周期性地运行命令或者shell脚本,通常被用在系统的自动化维护或者管理。
+
摘自 [[Wikipedia:Cron|Wikipedia]]:
 +
 
 +
:''cron'' 是一个在 Unix 及类似操作系统上执行计划任务的程序。用户可以在指定的时间段周期性地运行命令或 shell 脚本,通常用于系统的自动化维护或者管理。
  
 
==安装==
 
==安装==
  
有很多 cron 的实现,用户可以选择其一。{{Pkg|cronie}} 可以从 [core] 中获得,并且它被作为 '''base''' 软件组的一部分安装,你可以检查它是否正确安装:
+
cron 有多个实现程序,但是基础系统默认使用 [[systemd/Timers]],都没用安装,用户可以选择其一进行安装。[http://www.gentoo.org/doc/en/cron-guide.xml Gentoo Linux Cron 指南] 提供了一个这些实现之间的比较。软件包:
 +
 
 +
* {{Pkg|cronie}}
 +
* {{Pkg|fcron}}
 +
* {{AUR|dcron}}
 +
* {{AUR|vixie-cron}}
 +
* {{AUR|scron-git}}
 +
 
 +
==配置==
 +
 
 +
== 激活及开机启动 ==
 +
安装后,默认的守护进程不会启动。安装的软件包都提供了可以用 [[systemd#Using units|systemctl]] 控制的服务文件。例如 ''cronie'' 使用 {{ic|cronie.service}}.
 +
 
 +
{{ic|/etc/cron.daily/}} 目录包含当前的任务,启动 cron 服务时会触发所有当天任务。
 +
 
 +
{{Note|''cronie'' 提供了 {{ic|0anacron}}任务,每小时执行一次,可以执行其它因为未开机而延迟的任务。}}
 +
 
 +
=== 处理任务中的错误 ===
  
# pacman -S --needed cronie
+
cron 会记录 ''stdout'' 和 ''stderr'' 的输出并尝试通过 {{ic|sendmail}} 命令发送邮件给用户。如果 Cronie 未找到 {{ic|/usr/bin/sendmail}},则会禁用邮件通知。要发送邮件到用户的 spool,需要在系统上运行 smtp 进程,例如 {{Pkg|opensmtpd}}。也可以安装提供 sendmail 命令的软件包,然后配置成通过外部邮件服务器发送邮件。或者使用 {{ic|-m}} 选项将错误记录到日志并通过定制的脚本进行处理。
  
截至2011年5月,Arch Linux 默认的 cron 实现是 {{AUR|dcron}} (Dillon's Cron),它仍然被支持,可以从 [extra] 找到:
+
{{Tip|通过 [[Postfix#Local mail]] 可以发送邮件到本地系统。}}
  
# pacman -S dcron
+
# [[Edit|编辑]] {{ic|cronie.service}} 服务。
 +
# 安装 {{Pkg|esmtp}}, [[msmtp]], {{Pkg|opensmtpd}}, [[SSMTP|ssmtp]] 或编写自定义脚本。
  
另外,用户可以安装 {{Pkg|fcron}} (来自 [community]) 或者 {{AUR|bcron}}{{Broken package link|{{aur-mirror|bcron}}}} 或者 {{AUR|vixie-cron}} (来自 [[AUR]]); 它们都提供了广泛的功能和配置选项。
+
==== Example with ssmtp ====
  
[http://www.gentoo.org/doc/en/cron-guide.xml Gentoo Linux Cron 指南] 提供了一个这些实现之间的比较。
+
ssmtp is a send-only sendmail emulator which delivers email from a local computer to an smtp server. While there are currently no active maintainers, it is still by far the simplest way to transfer mail to a configured mailhub. There are no daemons to run, and configuration can be as simple as editing 3 lines in a single configuration file (if your host is trusted to relay unauthenticated email through your mailhub).  ssmtp does not receive mail, expand aliases, or manage a queue.  
  
==初始配置==
+
Install {{Pkg|ssmtp}}, which creates a symbolic link from {{ic|/usr/bin/sendmail}} to {{ic|/usr/bin/ssmtp}}. You must then edit {{ic|/etc/ssmtp/ssmtp.conf}}.  See [[SSMTP|ssmtp]] for details.  Creating a symbolic link to {{ic|/usr/bin/sendmail}} insures that programs like [[S-nail]] (or any package which provides {{ic|/usr/bin/mail}} will just work without modification.
{{注意|本部分内容已过期,暂时不翻译。}}<!--
 
{{Warning|The following sections of this article are still based on {{AUR|dcron}}: you are invited to check the validity of the contents below and fix what is out of date.}}
 
  
====Users & autostart====
+
Restart {{ic|cronie}} to insure that it detects that you now have a {{ic|/usr/bin/sendmail}} installed.
Cron should work "out-of-the-box" for most Arch Linux users. In order to use crontab, users must be members of a designated group, but in Arch Linux, that group is ''users'', of which all users should already be members. If for whatever reason some users are not members of this group, they can be added to it with the command:
 
  
# gpasswd -a ''username'' users
+
==== Example with msmtp ====
  
and they should then be able to edit their own crontabs.
+
Install {{Pkg|msmtp-mta}}, which creates a symbolic link from {{ic|/usr/bin/sendmail}} to {{ic|/usr/bin/msmtp}}. Restart {{ic|cronie}} to make sure it detects the new {{ic|sendmail}} command. You must then provide a way for {{ic|msmtp}} to convert your username into an email address.
  
To ensure cron starts on boot, add the ''crond'' daemon to the daemons array of [[rc.conf]]. See [[Daemon#Starting_on_Boot]] for details.
+
Then either add {{ic|MAILTO}} line to your crontab, like so:
  
====Handling errors of jobs====
+
<nowiki>MAILTO=your@email.com</nowiki>
Errors can occur during execution of jobs. When this happens cron register '''stderr''' output of job as e-mail and try to send it by default via '''sendmail''' command.
 
To log this message you can use '''-M''' option of crontd and write you own script or install rudimentary SMTP subsystem ('''esmtp''' in this example):
 
  
# pacman -S esmtp procmail
+
'''or''' create {{ic|/etc/msmtprc}} and append this line:
  
After installation create file {{ic|/etc/esmtprc}} with this content:
+
aliases /etc/aliases
  
identity myself@myisp.com
+
and create {{ic|/etc/aliases}}:
        hostname mail.myisp.com:25
 
        username "myself"
 
        password "secret"
 
        starttls enabled
 
        default
 
mda "/usr/bin/procmail -d %T"
 
Procmail needs root privileges to work in delivery mode but it is not an issue if you are running the cronjobs as root.
 
  
To test that everything works correctly, create a file {{ic|message.txt}} with ''"test message"'' in it.  
+
your_username: your@email.com
 +
# Optional:
 +
default: your@email.com
  
From the directory containing {{ic|message.txt}} run:  
+
Then [[Systemd#Editing provided units|modify the configuration]] of ''cronie'' daemon by replacing the {{ic|ExecStart}} command with:
  
  $ sendmail user_name < message.txt
+
  ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'
  
then:
+
==== Example with esmtp ====
  
$ cat /var/spool/mail/user_name
+
Install {{Pkg|esmtp}} and {{Pkg|procmail}}.
  
You should see in the terminal, the ''"test message"'', the time and date it was sent.
+
After installation configure the routing:
 +
{{hc|/etc/esmtprc|
 +
identity ''myself''@myisp.com
 +
      hostname mail.myisp.com:25
 +
      username ''"myself"''
 +
      password ''"secret"''
 +
      starttls enabled
 +
      default
 +
mda "/usr/bin/procmail -d %T"
 +
}}
  
Thats all, all error output of jobs now will be redirected to {{ic|/var/spool/mail/$user_name}}.
+
Procmail needs root privileges to work in delivery mode but it is not an issue if you are running the cronjobs as root anyway.
  
Due to the privileged issue, it is hard to create and send the email to root. So you could ask esmtp to forward all root's email to some ordinary users. Add the following lines in esmtprc
+
To test that everything works correctly, create a file {{ic|message.txt}} with {{ic|"test message"}} in it.
force_mda="user-name"
 
  
'''If the above test did not work''', try creating a file {{ic|~/.esmtprc}} with the same content as {{ic|/etc/esmtprc}}, (you can just create a copy as normal user).
+
From the same directory run:
  
Run the following command to make sure it has the correct 710 permission:  
+
$ sendmail ''user_name'' < message.txt
 +
 
 +
then:
 +
 
 +
$ cat /var/spool/mail/''user_name''
 +
 
 +
You should now see the test message and the time and date it was sent.
 +
 
 +
The error output of all jobs will now be redirected to {{ic|/var/spool/mail/''user_name''}}.
 +
 
 +
Due to the privileged issue, it is hard to create and send emails to root (e.g. {{ic|su -c ""}}). You can ask {{ic|esmtp}} to forward all root's email to an ordinary user with:
 +
{{hc|/etc/esmtprc|
 +
2=force_mda="''user-name''"
 +
}}
 +
 
 +
{{Note|If the above test didn't work, you may try creating a local configuration in {{ic|~/.esmtprc}} with the same content.
 +
 
 +
Run the following command to make sure it has the correct permission:  
  
 
  $ chmod 710 ~/.esmtprc
 
  $ chmod 710 ~/.esmtprc
  
Now just repeat the test with {{ic|message.txt}} exactly as before.
+
Then repeat the test with {{ic|message.txt}} exactly as before.}}
-->
+
 
 +
==== Example with opensmtpd ====
 +
 
 +
Install {{Pkg|opensmtpd}}.
 +
 
 +
Edit {{ic|/etc/smtpd/smtpd.conf}}. The following configuration allows for local delivery:
 +
 
 +
listen on localhost
 +
accept for local deliver to mbox
 +
 
 +
You can proceed to test it. First [[start]] {{ic|smtpd.service}}. Then do:
 +
$ echo test | sendmail user
 +
 
 +
''user'' can check his/her mail in with any [[:Category:Email clients|reader]] able to handle mbox format, or just have a look at the file {{ic|/var/spool/mail/''user''}}. If everything goes as expected, you can [[enable]] opensmtpd for future boots.
 +
 
 +
This approach has the advantage of not sending local cron notifications to a remote server. On the downside, you need a new daemon running.
 +
 
 +
{{Note|
 +
* At the moment of writing the Arch opensmtpd package does not create all needed directories under {{ic|/var/spool/smtpd}}, but the daemon will warn about that specifying the required ownerships and permissions. Just create them as suggested.
 +
* Even though the suggested configuration does not accept remote connections, it's a healthy precaution to add an additional layer of security blocking port 25 with [[iptables]] or similar.
 +
}}
 +
 
 +
==== Long cron job ====
 +
 
 +
Suppose this program is invoked by cron :
 +
 
 +
#!/bin/sh
 +
echo "I had a recoverable error!"
 +
sleep 1h
 +
 
 +
What happens is this:
 +
# cron runs the script
 +
# as soon as cron sees some output, it runs your MTA, and provides it with the headers. It leaves the pipe open, because the job hasn't finished and there might be more output.
 +
# the MTA opens the connection to postfix and leaves that connection open while it waits for the rest of the body.
 +
# postfix closes the idle connection after less than an hour and you get an error like this :
 +
smtpmsg='421 … Error: timeout exceeded' errormsg='the server did not accept the mail'
 +
 
 +
To solve this problem you can use the command chronic or sponge from {{Pkg|moreutils}}.
 +
From their respective man page:
 +
; chronic: chronic runs a command, and arranges for its standard out and standard error to only be displayed if the command fails (exits nonzero or crashes). If the command succeeds, any extraneous output will be hidden.
 +
; sponge: sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before opening the output file… If no output file is specified, sponge outputs to stdout.
 +
 
 +
Chronic too buffers the command output before opening its standard output.
 +
 
 
==Crontab 格式==
 
==Crontab 格式==
  

Revision as of 10:16, 18 April 2018

摘自 Wikipedia:

cron 是一个在 Unix 及类似操作系统上执行计划任务的程序。用户可以在指定的时间段周期性地运行命令或 shell 脚本,通常用于系统的自动化维护或者管理。

安装

cron 有多个实现程序,但是基础系统默认使用 systemd/Timers,都没用安装,用户可以选择其一进行安装。Gentoo Linux Cron 指南 提供了一个这些实现之间的比较。软件包:

配置

激活及开机启动

安装后,默认的守护进程不会启动。安装的软件包都提供了可以用 systemctl 控制的服务文件。例如 cronie 使用 cronie.service.

/etc/cron.daily/ 目录包含当前的任务,启动 cron 服务时会触发所有当天任务。

Note: cronie 提供了 0anacron任务,每小时执行一次,可以执行其它因为未开机而延迟的任务。

处理任务中的错误

cron 会记录 stdoutstderr 的输出并尝试通过 sendmail 命令发送邮件给用户。如果 Cronie 未找到 /usr/bin/sendmail,则会禁用邮件通知。要发送邮件到用户的 spool,需要在系统上运行 smtp 进程,例如 opensmtpd。也可以安装提供 sendmail 命令的软件包,然后配置成通过外部邮件服务器发送邮件。或者使用 -m 选项将错误记录到日志并通过定制的脚本进行处理。

Tip: 通过 Postfix#Local mail 可以发送邮件到本地系统。
  1. 编辑 cronie.service 服务。
  2. 安装 esmtp, msmtp, opensmtpd, ssmtp 或编写自定义脚本。

Example with ssmtp

ssmtp is a send-only sendmail emulator which delivers email from a local computer to an smtp server. While there are currently no active maintainers, it is still by far the simplest way to transfer mail to a configured mailhub. There are no daemons to run, and configuration can be as simple as editing 3 lines in a single configuration file (if your host is trusted to relay unauthenticated email through your mailhub). ssmtp does not receive mail, expand aliases, or manage a queue.

Install ssmtp, which creates a symbolic link from /usr/bin/sendmail to /usr/bin/ssmtp. You must then edit /etc/ssmtp/ssmtp.conf. See ssmtp for details. Creating a symbolic link to /usr/bin/sendmail insures that programs like S-nail (or any package which provides /usr/bin/mail will just work without modification.

Restart cronie to insure that it detects that you now have a /usr/bin/sendmail installed.

Example with msmtp

Install msmtp-mta, which creates a symbolic link from /usr/bin/sendmail to /usr/bin/msmtp. Restart cronie to make sure it detects the new sendmail command. You must then provide a way for msmtp to convert your username into an email address.

Then either add MAILTO line to your crontab, like so:

MAILTO=your@email.com

or create /etc/msmtprc and append this line:

aliases /etc/aliases

and create /etc/aliases:

your_username: your@email.com
# Optional:
default: your@email.com

Then modify the configuration of cronie daemon by replacing the ExecStart command with:

ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'

Example with esmtp

Install esmtp and procmail.

After installation configure the routing:

/etc/esmtprc
identity myself@myisp.com
       hostname mail.myisp.com:25
       username "myself"
       password "secret"
       starttls enabled
       default
mda "/usr/bin/procmail -d %T"

Procmail needs root privileges to work in delivery mode but it is not an issue if you are running the cronjobs as root anyway.

To test that everything works correctly, create a file message.txt with "test message" in it.

From the same directory run:

$ sendmail user_name < message.txt 

then:

$ cat /var/spool/mail/user_name

You should now see the test message and the time and date it was sent.

The error output of all jobs will now be redirected to /var/spool/mail/user_name.

Due to the privileged issue, it is hard to create and send emails to root (e.g. su -c ""). You can ask esmtp to forward all root's email to an ordinary user with:

/etc/esmtprc
force_mda="user-name"
Note: If the above test didn't work, you may try creating a local configuration in ~/.esmtprc with the same content.

Run the following command to make sure it has the correct permission:

$ chmod 710 ~/.esmtprc
Then repeat the test with message.txt exactly as before.

Example with opensmtpd

Install opensmtpd.

Edit /etc/smtpd/smtpd.conf. The following configuration allows for local delivery:

listen on localhost
accept for local deliver to mbox

You can proceed to test it. First start smtpd.service. Then do:

$ echo test | sendmail user

user can check his/her mail in with any reader able to handle mbox format, or just have a look at the file /var/spool/mail/user. If everything goes as expected, you can enable opensmtpd for future boots.

This approach has the advantage of not sending local cron notifications to a remote server. On the downside, you need a new daemon running.

Note:
  • At the moment of writing the Arch opensmtpd package does not create all needed directories under /var/spool/smtpd, but the daemon will warn about that specifying the required ownerships and permissions. Just create them as suggested.
  • Even though the suggested configuration does not accept remote connections, it's a healthy precaution to add an additional layer of security blocking port 25 with iptables or similar.

Long cron job

Suppose this program is invoked by cron :

#!/bin/sh
echo "I had a recoverable error!"
sleep 1h

What happens is this:

  1. cron runs the script
  2. as soon as cron sees some output, it runs your MTA, and provides it with the headers. It leaves the pipe open, because the job hasn't finished and there might be more output.
  3. the MTA opens the connection to postfix and leaves that connection open while it waits for the rest of the body.
  4. postfix closes the idle connection after less than an hour and you get an error like this :
smtpmsg='421 … Error: timeout exceeded' errormsg='the server did not accept the mail'

To solve this problem you can use the command chronic or sponge from moreutils. From their respective man page:

chronic
chronic runs a command, and arranges for its standard out and standard error to only be displayed if the command fails (exits nonzero or crashes). If the command succeeds, any extraneous output will be hidden.
sponge
sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before opening the output file… If no output file is specified, sponge outputs to stdout.

Chronic too buffers the command output before opening its standard output.

Crontab 格式

crontab 的基本格式是:

<分钟> <小时> <日> <月份> <星期> <命令>
  • 分钟 值从 0 到 59.
  • 小时 值从 0 到 23.
  • 值从 1 到 31.
  • 值从 1 到 12.
  • 星期 值从 0 到 6, 0 代表星期日.

多个时间可以用逗号隔开,范围可以用连字符给出,星号可以作为通配符。空格用来分开字段。例如,下面一行:

*0,*5 9-16 * 1-5,9-12 1-5 /home/user/bin/i_love_cron.sh

会在夏天(六、七、八月)之外的每周周一到周五的上午9点到下午4点之间每5分钟执行一次 i_love_cron.sh。更多范例和高级配置方法见下文。

基本命令

Crontabs 不应该直接编辑;用户应该使用 crontab 程序来处理他们的 crontabs。为了能够访问这个命令,用户必须添加到 users 用户组 (见 gpasswd 命令).

要查看 crontabs,用户应该运行下面的命令:

$ crontab -l

要编辑 crontabs,可以使用:

$ crontab -e

要移除 crontabs, 可以使用:

$ crontab -d

如果用户有一个保存好的 crontab 想要用它完全覆盖旧的 crontab,可以使用:

$ crontab saved_crontab_filename

想从命令行(Wikipedia:stdin)覆盖一个 crontab,使用:

$ crontab - 

想编辑别的用户的 crontab, 使用root运行下面的命令:

# crontab -u username -e

同一个格式 (追加 "-u username" 到命令后) 也可以用来列出或删除 crontabs。

如果想使用 nano 而不是 vi 作为 crontab 编辑器,添加下面的变量到 /etc/bash.bashrc:

export EDITOR="/usr/bin/nano"

然后重启终端

范例

下面的条目:

01 * * * * /bin/echo Hello, world!

将会在每个月的每一天的每一个小时的第一分钟(例如,在12:01,1:01,2:01等)执行命令 /bin/echo Hello, world!

类似地,

*/5 * * jan mon-fri /bin/echo Hello, world!

将会在一月的每个工作日每五分钟(例如,在12:00,12:05,12:10等)执行一次相同的命令。

As noted in the Crontab Format section, the line:

*0,*5 9-16 * 1-5,9-12 1-5 /home/user/bin/i_love_cron.sh

Will execute the script i_love_cron.sh at five minute intervals from 9 AM to 5 PM (excluding 5 PM itself) every weekday (Mon-Fri) of every month except during the summer (June, July, and August).

更多信息

The cron daemon parses a configuration file known as crontab. Each user on the system can maintain a separate crontab file to schedule commands individually. The root user's crontab is used to schedule system-wide tasks (though users may opt to use /etc/crontab or the /etc/cron.d directory, depending on which cron implementation they choose).

There are slight differences between the crontab formats of the different cron daemons. The default root crontab for dcron looks like this:

/var/spool/cron/root
# root crontab
# DO NOT EDIT THIS FILE MANUALLY! USE crontab -e INSTEAD

# man 1 crontab for acceptable formats:
#    <minute> <hour> <day> <month> <dow> <tags and command>
#    <@freq> <tags and command>

# SYSTEM DAILY/WEEKLY/... FOLDERS
@hourly         ID=sys-hourly   /usr/sbin/run-cron /etc/cron.hourly
@daily          ID=sys-daily    /usr/sbin/run-cron /etc/cron.daily
@weekly         ID=sys-weekly   /usr/sbin/run-cron /etc/cron.weekly
@monthly        ID=sys-monthly  /usr/sbin/run-cron /etc/cron.monthly

These lines exemplify one of the formats that crontab entries can have, namely whitespace-separated fields specifying:

  1. @period
  2. ID=jobname (this tag is specific to dcron)
  3. command

The other standard format for crontab entries is:

  1. minute
  2. hour
  3. day
  4. month
  5. day of week
  6. command

The crontab files themselves are usually stored as /var/spool/cron/username. For example, root's crontab is found at /var/spool/cron/root

See the crontab man page for further information and configuration examples.

run-parts issue

cronie使用run-parts来执行在cron.hourly/cron.daily/cron.weekly/cron.monthly里的脚本。 请注意这些文件夹里的脚本名字中不应该含有'.',因为不含有任何参数的run-parts将会忽略他们。例如backup.sh这个脚本是不会被执行的,请将其改名为backup或者其他不含有'.'的名字以定时执行该脚本。 要获取更详细的信息请 man run-parts

运行 X 程序

If you find that you cannot run X apps from cron jobs then put this before the command:

export DISPLAY=:0.0 ;

That sets the DISPLAY variable to the first display; which is usually right unless you like to run multiple xservers on your machine.

If it still does not work then you need to use xhost to give your user control over X11:

# xhost +si:localuser:$(whoami)

I put it in my gnome `Startup Applications' like this:

bash -c "xhost +si:localuser:$(whoami)"

Asynchronous job processing

If you regularly turn off your computer but do not want to miss jobs, there are some solutions available (easiest to hardest):

Dcron

Vanilla dcron supports asynchronous job processing. Just put it with @hourly, @daily, @weekly or @monthly with a jobname, like this:

@hourly         ID=greatest_ever_job      echo This job is very useful.

Cronwhip

(AUR, forum thread): Script to automatically run missed cron jobs; works with the default cron implementation, dcron.

Anacron

(AUR): Full replacement for dcron, processes jobs asynchronously.

Fcron

(Community, forum thread): Like anacron, fcron assumes the computer is not always running and, unlike anacron, it can schedule events at intervals shorter than a single day. Like cronwhip, it can run jobs that should have been run during the computer's downtime.

参见