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 将您的用户名转换为电子邮件地址。
在 crontab 中添加 MAILFROM 行
MAILFROM=your@email.com
MAILFROM,smtp 服务器可能会抱怨标头错误。然后,要么在 crontab 中添加 MAILTO 行,如下所示
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 作业,则这不是问题。
要测试一切是否正常工作,请创建一个名为 message.txt 的文件,其中包含 "test message"。
从同一目录运行
$ sendmail user_name < message.txt
然后
$ cat /var/spool/mail/user_name
您现在应该会看到测试消息以及发送的时间和日期。
所有作业的错误输出现在都将重定向到 /var/spool/mail/用户名。
由于权限问题,很难创建和发送电子邮件给 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/用户。如果一切如预期进行,您可以 启用 opensmtpd 以便将来启动。
这种方法的好处是不会将本地 cron 通知发送到远程服务器。缺点是您需要运行一个新的守护进程。
- 在撰写本文时,Arch 的 opensmtpd 软件包并未在
/var/spool/smtpd下创建所有必需的目录,但守护进程会为此发出警告,并指定所需的拥有者和权限。只需按建议创建它们。 - 尽管建议的配置不接受远程连接,但添加额外的安全层来阻止端口 25(使用 iptables 或类似工具)是一种健康的预防措施。
长时间运行的 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'
要解决此问题,您可以使用 chronic 或 sponge 命令,它们来自 moreutils。摘自它们各自的手册页:
- 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(包括 9 点,但不包括 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
更多示例和高级配置技术可以在下面找到。
基本命令
Crontabs 绝不应直接编辑;相反,您应该使用 crontab 程序来处理您的 crontabs。
查看您的 crontabs
$ crontab -l
编辑您的 crontabs
$ crontab -e
删除您*所有*的 crontabs
$ crontab -r
如果您有一个已保存的 crontab 并想完全覆盖您旧的 crontab
$ crontab saved_crontab_filename
从命令行覆盖 crontab(Wikipedia:stdin)
$ crontab -
编辑别人的 crontab
# crontab -u username -e
相同的格式(在命令后附加 -u 用户名)也适用于列出和删除 crontabs。
示例
条目
01 * * * * /bin/echo Hello, world!
在每小时的每时每分的第 1 分钟运行命令 /bin/echo Hello, world!(即在 12:01、1:01、2:01 等)。
类似地
*/5 * * jan mon-fri /bin/echo Hello, world!
在一月份的每个工作日每五分钟运行相同的作业(即在 12:00、12:05、12:10 等)。
该行(如 crontab(5) 中所述)
*/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: archie # mm hh DD MM W /path/program [--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 Tuesdays, Wednesdays and Fridays." 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 * * 1-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
标准的 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 时,请注意,spool 目录是 /var/spool/fcron,并且使用 fcrontab 命令而不是 crontab 来编辑用户 crontabs。这些 crontabs 以二进制格式存储,文本版本位于旁边,在 spool 目录中为 foo.orig。任何手动编辑用户 crontabs 的脚本可能需要调整,因为这种行为存在差异。
一个可能有助于将传统用户 crontabs 转换为 fcron 格式的快速脚本:
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} ... 等中的任何任务(包括 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 条目的另一种标准格式是:
- minute
- hour
- day
- month
- day of week
- command
crontab 文件本身通常存储为 /var/spool/cron/username。例如,root 的 crontab 位于 /var/spool/cron/root。
有关进一步信息和配置示例,请参阅 crontab man page。
参见
- Gentoo Linux Cron 指南
- crontab.guru - 在线 cronjob 表达式编辑器
- cron-notifyAUR 是一个符合 FreeDesktop.org 的通知服务,它会在执行命令前定期请求确认。命令在自定义配置文件中配置。