cron
来自 Wikipedia
- cron 是类 Unix 计算机操作系统中基于时间的作业调度器。 cron 使用户能够调度作业(命令或 shell 脚本)在特定的时间、日期或间隔定期运行。它通常用于自动化系统维护或管理。
安装
有许多 cron 实现,但默认情况下未安装任何实现,因为基本系统使用 systemd/Timers 代替。请参阅 Gentoo wiki 的 cron 指南,其中提供了比较。
可用软件包
- cronie
- fcron
- dcronAUR
- vixie-cronAUR
- scron-gitAUR
配置
激活和自动启动
安装后,守护进程默认不会启用。已安装的软件包可能提供一个服务,可以使用 systemctl 进行控制。例如,cronie 使用 cronie.service
。
检查 /etc/cron.daily/
和类似目录以查看存在哪些任务。激活 cron 服务将触发所有这些任务。
0anacron
每小时 任务,这允许延迟运行其他任务,例如,如果计算机在标准执行时刻被关闭。处理任务错误
cron 注册来自 stdout 和 stderr 的输出,并尝试通过 sendmail
命令将其作为电子邮件发送到用户的邮件池。如果未找到 /usr/bin/sendmail
,Cronie 将禁用邮件输出。为了将邮件写入用户的邮件池,系统上必须运行 smtp 守护进程,例如 opensmtpd。否则,您可以安装一个提供 sendmail 命令的软件包,并将其配置为将邮件发送到远程邮件交换器。您还可以使用 -m
选项并编写自定义脚本来记录消息。
sSMTP 示例
sSMTP 是一个仅发送邮件的 sendmail 模拟器,它将来自本地计算机的电子邮件传递到 smtp 服务器。虽然目前没有活跃的维护者,但它仍然是将邮件传输到配置的邮件枢纽的最简单方法。没有要运行的守护进程,并且配置可以简单到编辑单个配置文件中的 3 行(如果您的主机被信任通过您的邮件枢纽中继未经身份验证的电子邮件)。sSMTP 不接收邮件、展开别名或管理队列。
安装 ssmtpAUR,它创建一个从 /usr/bin/sendmail
到 /usr/bin/ssmtp
的符号链接。然后您必须编辑 /etc/ssmtp/ssmtp.conf
。有关详细信息,请参阅 sSMTP。创建到 /usr/bin/sendmail
的符号链接可确保像 S-nail(或任何提供 /usr/bin/mail
的软件包)这样的程序无需修改即可正常工作。
重启 cronie.service
以确保它检测到您现在已安装了 /usr/bin/sendmail
。
msmtp 示例
安装 msmtp-mta,它创建一个从 /usr/bin/sendmail
到 /usr/bin/msmtp
的符号链接。重启 cronie.service
以确保它检测到新的 sendmail
命令。然后您必须提供一种方法,使 msmtp
将您的用户名转换为电子邮件地址。
然后将 MAILTO
行添加到您的 crontab 中,如下所示
MAILTO=your@email.com
或者 创建 /etc/msmtprc
并追加此行
aliases /etc/aliases
并创建 /etc/aliases
your_username: your@email.com # Optional: default: your@email.com
然后修改 cronie 守护进程的配置,方法是将 ExecStart
命令替换为
ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'
esmtp 示例
安装后配置路由
/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 需要 root 权限才能在传递模式下工作,但如果您以 root 身份运行 cron 作业,则这不是问题。
要测试一切正常工作,请创建一个包含 "test message"
的文件 message.txt
。
从同一目录运行
$ sendmail user_name < message.txt
然后
$ cat /var/spool/mail/user_name
您现在应该看到测试消息以及发送的时间和日期。
所有作业的错误输出现在将重定向到 /var/spool/mail/user_name
。
由于权限问题,很难创建电子邮件并将其发送给 root 用户(例如 su -c ""
)。您可以要求 esmtp
将所有 root 用户的电子邮件转发给普通用户,使用
/etc/esmtprc
force_mda="user-name"
~/.esmtprc
中创建具有相同内容的本地配置。运行以下命令以确保它具有正确的权限
$ chmod 710 ~/.esmtprc然后完全按照之前的操作,使用
message.txt
重复测试。opensmtpd 示例
安装 opensmtpd。
编辑 /etc/smtpd/smtpd.conf
。以下配置允许本地传递
listen on localhost action "local" mbox alias <aliases> match for local action "local"
您可以继续进行测试。首先启动 smtpd.service
。然后执行
$ echo test | sendmail user
用户 可以使用任何能够处理 mbox 格式的 阅读器 检查他们的邮件,或者只需查看文件 /var/spool/mail/user
。如果一切按预期进行,您可以启用 opensmtpd 以供将来启动。
这种方法的优点是不将本地 cron 通知发送到远程服务器。缺点是您需要运行新的守护进程。
- 在编写本文时,Arch opensmtpd 软件包未在
/var/spool/smtpd
下创建所有需要的目录,但守护进程会发出警告,说明所需的属主和权限。只需按照建议创建它们即可。 - 即使建议的配置不接受远程连接,但使用 iptables 或类似工具阻止端口 25 也是一种健康的预防措施,可以增加额外的安全层。
长时间运行的 cron 任务
假设此程序由 cron 调用
#!/bin/sh echo "I had a recoverable error!" sleep 1h
发生的情况是这样的
- cron 运行脚本
- 一旦 cron 看到一些输出,它就会运行您的 MTA,并为其提供标头。它保持管道打开,因为作业尚未完成,并且可能还有更多输出。
- MTA 打开与 postfix 的连接,并在等待正文的其余部分时保持该连接打开。
- postfix 在不到一小时后关闭空闲连接,您会收到类似这样的错误
smtpmsg='421 … Error: timeout exceeded' errormsg='the server did not accept the mail'
要解决此问题,您可以使用 moreutils 中的命令 chronic 或 sponge。摘自它们各自的 man 手册
- chronic(1)
- chronic 运行一个命令,并安排仅当命令失败(非零退出或崩溃)时才显示其标准输出和标准错误。如果命令成功,则任何无关的输出都将被隐藏。
- sponge(1)
- sponge 读取标准输入并将其写入指定的文件。与 shell 重定向不同,sponge 在打开输出文件之前会吸收所有输入…… 如果未指定输出文件,则 sponge 输出到 stdout。
Chronic 也会缓冲命令输出,然后再打开其标准输出。
Crontab 格式
crontab 的基本格式是
minute hour day_of_month month day_of_week command
- 分钟 值可以是 0 到 59。
- 小时 值可以是 0 到 23。
- 日 值可以是 1 到 31。
- 月份 值可以是 1 到 12。
- 星期 值可以是 0 到 6,其中 0 表示星期日。
空格用于分隔字段。要微调您的计划,您还可以使用以下符号之一
符号 | 描述 |
---|---|
* | 通配符,指定每个可能的时间间隔 |
, | 列出多个值,以逗号分隔。 |
- | 指定两个数字之间的范围,用连字符分隔 |
/ | 使用斜杠指定周期/频率 |
例如,以下行
*/5 9-16 * 1-5,9-12 1-5 ~/bin/i_love_cron.sh
将在工作日的上午 9 点到下午 4:55 之间,每五分钟执行一次脚本 i_love_cron.sh
,但六月、七月和八月除外。
此外,crontab 还有一些特殊关键字
关键字 | 描述 |
---|---|
@reboot | 启动时 |
@yearly | 每年一次 |
@annually | 与 @yearly 相同 |
@monthly | 每月一次 |
@weekly | 每周一次 |
@daily | 每天一次 |
@midnight | 与 @daily 相同 |
@hourly | 每小时一次 |
例如
@reboot ~/bin/i_love_cron.sh
将在启动时执行脚本 i_love_cron.sh
。
更多信息请参阅: https://www.adminschoice.com/crontab-quick-reference
更多示例和高级配置技术可以在下面找到。
基本命令
永远不要直接编辑 Crontab;相反,您应该使用 crontab
程序来处理您的 crontab。
查看您的 crontab
$ crontab -l
编辑您的 crontab
$ crontab -e
删除所有您的 crontab
$ crontab -r
如果您有已保存的 crontab 并且想要完全覆盖您的旧 crontab
$ crontab saved_crontab_filename
从命令行覆盖 crontab (Wikipedia:stdin)
$ crontab -
编辑其他用户的 crontab
# crontab -u username -e
相同的格式(在命令后附加 -u username
)也适用于列出和删除 crontab。
示例
条目
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 等)。
该行(如 crontab(5) 中所述)
*0,*5 9-16 * 1-5,9-12 1-5 /home/user/bin/i_love_cron.sh
将在每个工作日(周一至周五),除夏季(六月、七月和八月)以外的每个月的上午 9 点到下午 5 点(不包括下午 5 点本身)以五分钟的间隔执行脚本 i_love_cron.sh
。
定期设置也可以像此 crontab 模板中一样输入
# Chronological table of program loadings # Edit with "crontab" for proper functionality, "man 5 crontab" for formatting # User: johndoe # mm hh DD MM W /path/progam [--option]... ( W = weekday: 0-6 [Sun=0] ) 21 01 * * * /usr/bin/systemctl hibernate @weekly $HOME/.local/bin/trash-empty
以下是一些不言自明的 crontab 语法示例
30 4 echo "It is now 4:30 am." 0 22 echo "It is now 10 pm." 30 15 25 12 echo "It is 3:30pm on Christmas Day." 30 3 * * * echo "Remind me that it's 3:30am every day." 0 * * * * echo "It is the start of a new hour." 0 6 1,15 * * echo "At 6am on the 1st and 15th of every month." 0 6 * * 2,3,5 echo "At 6am on Tuesday, Wednesday and Thursdays." 59 23 * * 1-5 echo "Just before midnight on weekdays." 0 */2 * * * echo "Every two hours." 0 20 * * 4 echo "8pm on a Thursday." 0 20 * * Thu echo "8pm on a Thursday." */15 9-17 * * 2-5 echo "Every 15 minutes from 9am-5pm on weekdays." @yearly echo "Happy New Year!"
默认编辑器
要使用备用默认编辑器,请在 shell 初始化脚本中定义 EDITOR
环境变量,如 环境变量 中所述。
作为普通用户,需要使用 su
而不是 sudo
才能正确拉取环境变量
$ su -c "crontab -e"
要对此 printf
设置别名,需要携带任意字符串,因为 su
会在新 shell 中启动
alias scron="su -c $(printf "%q " "crontab -e")"
运行基于 X.org 服务器的应用程序
Cron 不在 X.org 服务器下运行,因此它无法知道启动 X.org 服务器应用程序所需的环境变量,因此必须定义这些变量。可以使用像 xuserrun-gitAUR 这样的程序来完成它
17 02 * ... /usr/bin/xuserrun /usr/bin/xclock
或者可以手动定义它们(echo $DISPLAY
将给出当前的 DISPLAY 值)
17 02 * ... env DISPLAY=:0 /usr/bin/xclock
如果在 cron 中运行 notify-send 以进行桌面通知,notify-send 会将值发送到 dbus。因此它需要告诉 dbus 连接到正确的总线。地址可以通过检查 DBUS_SESSION_BUS_ADDRESS 环境变量并将其设置为相同的值来找到。因此
17 02 * ... env DBUS_SESSION_BUS_ADDRESS=your-address notify-send 'Foo bar'
如果通过例如 SSH 完成,则需要授予权限
# xhost +si:localuser:$(whoami)
异步作业处理
如果您经常关闭计算机,但又不想错过作业,则有一些可用的解决方案(从最容易到最难)
Cronie
cronie 附带 anacron。项目主页说
Cronie 包含标准的 UNIX 守护进程 crond,它在预定的时间运行指定的程序以及相关工具。它基于原始 cron,并具有安全性和配置增强功能,例如使用 pam 和 SELinux 的能力。
Dcron
Vanilla dcronAUR 支持异步作业处理。只需将其与 @hourly、@daily、@weekly 或 @monthly 以及作业名称一起放置,就像这样
@hourly ID=greatest_ever_job echo This job is very useful.
Cronwhip
cronwhipAUR 是一个自动运行错过的 cron 作业的脚本;它与以前的默认 cron 实现 dcron 一起工作。另请参阅 论坛帖子。
Anacron
Anacron 是 dcron 的完全替代品,它可以异步处理作业。
它由 cronie 提供。配置文件是 /etc/anacrontab
。有关格式的信息可以在 anacrontab(5) 中找到。运行 anacron -T
将测试 /etc/anacrontab
的有效性。
Fcron
与 anacron 类似,fcron 假设计算机并非始终运行,并且与 anacron 不同,它可以安排短于一天的间隔的事件,这对于经常挂起/休眠的系统(例如笔记本电脑)可能很有用。与 cronwhip 类似,fcron 可以运行在计算机停机期间应该运行的作业。
当用 fcron 替换 cronie 时,请注意后台处理目录是 /var/spool/fcron
,并且使用 fcrontab
命令而不是 crontab 来编辑用户 crontab。这些 crontab 以二进制格式存储,文本版本与它们相邻,在后台处理目录中为 foo.orig。由于行为上的这种差异,任何手动编辑用户 crontab 的脚本可能都需要调整。
一个可以帮助将传统用户 crontab 转换为 fcron 格式的快速 scriptlet
cd /var/spool/cron && ( for ctab in *; do fcrontab ${ctab} -u ${ctab} done )
另请参阅 论坛帖子。
确保排他性
如果您运行可能长时间运行的作业(例如,由于许多更改或特定的慢速网络连接,备份可能会突然运行很长时间),则 flock
(util-linux) 可以确保 cron 作业不会第二次启动。
5,35 * * * * /usr/bin/flock -n /tmp/lock.backup /root/make-backup.sh
Cronie
cronie 的相关文件层次结构如下
/etc/ |----- cron.d/ | ----- 0hourly |----- cron.minutely/ |----- cron.hourly/ | ----- 0anacron |----- anacrontab |----- cron.daily/ |----- cron.monthly/ |----- cron.weekly/ |----- crontab |----- cron.deny
Cronie 同时提供 cron 和 anacron 功能:cron 以规则的时间间隔(精确到一分钟)运行作业,只要系统在指定的时间可用,而 anacron 以天为单位指定的时间间隔执行命令。与 cron 不同,它不假设系统持续运行。每当系统启动时,anacron 都会检查是否有任何应该运行的作业,并相应地处理它们。
cron 作业可以在 /etc/cron.d
目录中的类似 crontab 的文件中定义,也可以在 /etc/crontab
文件中添加。请注意,后者默认情况下不存在,但如果存在则会使用。按照 /etc/cron.d/0hourly
的指示,/etc/cron.hourly
中的任何可执行文件都将每小时运行一次(默认情况下在每小时的第 1 分钟)。如果 /etc/cron.d/0minutely
中相应地指示,则 /etc/cron.minutely
中的文件每分钟执行一次。可执行文件通常是 shell 脚本,也可以使用指向可执行文件的符号链接。/etc/cron.deny
文件包含不允许使用 crontab 的用户列表,如果没有此文件,则只有 /etc/cron.allow
中列出的用户可以使用它。
Anacron 的工作方式类似,通过执行 /etc/cron.daily
、/etc/cron.weekly
和 /etc/cron.monthly
目录中的文件,这些文件根据所需的作业频率放置在那里。cron 作业 /etc/cron.hourly/0anacron
确保 anacron 每天运行一次以执行其待处理的任务。
- Cronie 使用
run-parts
来执行不同目录中的脚本。文件名不应包含任何点 (.),因为run-parts
在其默认模式下会静默忽略它们(请参阅 run-parts(8))。名称必须仅包含大写和小写字母、数字、下划线和减号。 systemctl status cronie
的输出可能会显示诸如CAN'T OPEN (/etc/crontab): No such file or directory
之类的消息。但是,这可以忽略,因为 cronie 不需要它。- Cronie 对
/etc/cron.d/0hourly
的权限特别敏感。如果/etc/cron.d/0hourly
损坏或权限不正确,则/etc/cron.d/{hourly,weekly,daily} ... etc
中的任何任务(包括 anacron 启动器)都不会运行。pacman -Qkk cronie
可以显示您是否有任何此类问题。
>/dev/null 2>&1
以将输出重定向到 /dev/null。0 1 5 10 * /path/to/script.sh >/dev/null 2>&1您还可以在 crontab 文件中设置
MAILTO=””
变量以禁用电子邮件警报。Dcron
cron 守护程序解析一个名为 crontab
的配置文件。系统上的每个用户都可以维护一个单独的 crontab 文件来单独计划命令。root 用户的 crontab 用于计划系统范围的任务(尽管用户可以选择使用 /etc/crontab
或 /etc/cron.d
目录,具体取决于他们选择的 cron 实现)。
/var/spool/cron/root
# Run command at a scheduled time # Edit this 'crontab -e' for error checking, man 1 crontab for acceptable format # <@freq> <tags and command> @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 # mm hh DD MM W /path/command (or tags) # W = week: 0-6, Sun=0 21 01 * * * /usr/bin/systemctl suspend
这些行例举了 crontab 条目可以具有的格式之一,即空格分隔的字段,指定
- @period
- ID=jobname(此标签特定于 dcron)
- command
crontab 条目的另一个标准格式是
- 分钟
- 小时
- 日
- 月
- 星期几
- command
crontab 文件本身通常存储为 /var/spool/cron/username
。例如,root 的 crontab 位于 /var/spool/cron/root
有关更多信息和配置示例,请参阅 crontab 手册页。
另请参阅
- Gentoo Linux Cron 指南
- crontab.guru - cronjob 表达式的在线编辑器
- cron-notifyAUR 是一个与 FreeDesktop.org 兼容的通知服务,用于定期请求在执行命令之前确认。命令在自定义配置文件中配置。