如何通过脚本创建 crontab

228

我需要通过运行脚本来添加一个cron job以设置服务器。我目前正在使用Ubuntu操作系统。我可以使用crontab -e,但那会打开一个编辑器来编辑当前的cron表。我想以编程方式完成这个任务。

这种做法可行吗?


https://dev59.com/MnRB5IYBdhLWcg3weXOX - dskrvk
2
可能是重复的问题,参考如何以编程方式创建新的cron作业? - Twonky
如果您想修改或删除crontab条目,请查看下面我的解决方案。 - Brian Smith
15个回答

537

这里有一个一行代码的方法,不需要/要求新工作在文件中:

(crontab -l 2>/dev/null; echo "*/5 * * * * /path/to/job -with args") | crontab -

2>/dev/null 很重要,因为它可以避免一些 *nix 系统在没有 crontab 记录时输出 no crontab for username 信息。


20
这应该是被接受的答案。现在只需要找到一种方法来检查我打算添加的单行代码是否已经存在了,但不改变原意。 - ChrisPrime
11
在我使用脚本添加之前,我希望你能翻译一下如何检查某个东西是否在我的用户crontab中:https://dev59.com/6GYq5IYBdhLWcg3weQgy#14451184 - ChrisPrime
3
如果此脚本旨在作为命令重复执行并修改现有的cron任务,则最好替换crontab中的现有行。可以使用多个标记来控制不同的cron任务(control-marker-1,control-marker-2等): (crontab -l 2> / dev / null | grep -v control-marker-1; echo '*/5 * * * * /path/to/job -with args #control-marker-1')| crontab - - chef
9
我发现这个操作会删除已有的crontab条目,而且我需要使用另一个用户(root),所以我使用了以下命令来保留已有的条目: echo -e "$(sudo crontab -u root -l)\n* * * * * echo hello > /home/danny/temp.log 2>&1" | sudo crontab -u root - 希望这能帮助到某些人。 - Danny
1
如果你使用了 "set -e",请务必查看下面的链接 https://dev59.com/ym445IYBdhLWcg3wZJew#51497394,因为这种方式会以令人困惑的方式悄悄地失败。感谢 @Faria! - runamok
显示剩余8条评论

72

对于用户的定时任务(包括 root 用户),您可以执行以下操作:

crontab -l -u user | cat - filename | crontab -u user -

有一个名为“filename”的文件,其中包含要追加的项目。您也可以使用sed或其他工具进行文本操作,而不是使用cat。 您应该使用crontab命令而不是直接修改文件。

类似的操作如下:

{ crontab -l -u user; echo 'crontab spec'; } | crontab -u user -

如果您正在修改或创建系统定时任务,那么这些任务可以像普通文本文件一样进行操作。它们存储在/etc/cron.d/etc/cron.hourly/etc/cron.daily/etc/cron.weekly/etc/cron.monthly目录和文件/etc/crontab/etc/anacrontab中。


看起来很有前途,但是尝试第二种方法(使用echo),我得到了“crontab: usage error: file name must be specified for replace.”的错误。Cron man页面显示语法为crontab [ -u user ] file,即必须指定文件名。有什么诀窍可以让它接受管道数据吗? - Mark Berry
1
@MarkBerry:非常抱歉。在管道中,必须使用连字符来表示输入来自“stdin”。我会更正我的答案。 - Dennis Williamson

40

在Ubuntu及许多其他发行版中,您可以将一个文件放入/etc/cron.d目录中,其中包含一个带有有效crontab条目的单行。不需要向现有文件添加一行。

如果您只需要每天运行某个东西,只需将文件放入/etc/cron.daily中即可。同样,您还可以将文件放入/etc/cron.hourly/etc/cron.monthly/etc/cron.weekly中。


8
但是您必须拥有 root 权限才能执行此操作。 - Keith
@IvanGoneKrazy - 任何我需要在每次重启时运行的文件夹吗? - Koder101

32

Joe Casadonte的一行代码非常完美,但是如果你使用set -e运行,也就是说,如果你的脚本设置为在出现错误时失败,并且还没有cronjobs,那么这个一行代码将不会创建cronjob,但也不会停止脚本。这种无声的失败可能会非常误导人。

原因是crontab -l返回一个1返回码,导致后续命令(echo)不被执行...因此cronjob未被创建。但由于它们作为子进程执行(因为括号),它们不会停止脚本。

(有趣的是,如果你再次运行相同的命令,它将起作用:一旦你执行了crontab -一次,crontab -l仍然不输出任何内容,但它不再返回错误(你不再收到no crontab for <user>消息)。因此,后续的echo被执行,cronjob被创建)

无论如何,如果你使用 set -e,那么这行代码必须是:
(crontab -l 2>/dev/null || true; echo "*/5 * * * * /path/to/job -with args") | crontab -

是的,这个更加完美。 - Yngve Sneen Lindal
不错啊 - 希望它能给你带来缺失的声誉! - Jan Mirus
我找到的唯一有用的解决方案。 - Kamal Chaturvedi

24

Crontab文件只是文本文件,可以像处理其他文本文件一样处理。 crontab命令的目的是使编辑crontab文件更加安全。 通过该命令编辑时,系统会检查文件是否存在错误,如果没有错误,则保存。

crontab [文件路径] 可以用于指定存储在文件中的crontab。与crontab -e类似,只有文件没有错误时才会安装。

因此,脚本可以直接编写cron tab文件,或将其写入临时文件并使用crontab [临时文件路径]命令加载。 直接编写可避免编写临时文件,但也避免了安全检查。


2
对于像我这样的新手,注意是 crontab [文件路径] .. 这绝对是最好的选择,因为它允许更易读的代码。我使用 crontab 跟踪包裹并根据状态更改桌面壁纸。当我不期望包裹时,它不需要每小时都检查。这就是为什么我希望脚本可以自动编辑 cron 频率的原因。 - Rasmus
1
@Rasmus,那听起来是一个很棒的脚本,我很想能够借鉴一下。有没有通过gist或类似方式分享的机会呢? - cledoux
只是提醒一下,crontab [文件路径] 不一定需要一个“临时”文件,它可以加载任何按照 crontab 布局正确格式化的文件。这是我们在 SlickStack 中使用的方法,因此 crontab 模板可以随时更新(下载)并重新安装:https://github.com/littlebizzy/slickstack/blob/master/00-crontab.txt - Jesse Nickles

21

给你一个更简单的答案:

echo "0 1 * * * /root/test.sh" | tee -a /var/spool/cron/root

您可以按以下方式在远程服务器上设置cron作业:

#!/bin/bash
servers="srv1 srv2 srv3 srv4 srv5"
for i in $servers
  do
  echo "0 1 * * * /root/test.sh" | ssh $i " tee -a /var/spool/cron/root"
done
在Linux中,crontab文件的默认位置是/var/spool/cron/。在这里,您可以找到所有用户的crontab文件。您只需要将您的cron作业条目附加到相应用户的文件中即可。在上面的示例中,root用户的crontab文件正在添加一个cron作业以在每天凌晨1点运行/root/test.sh

在Ubuntu上,这将是/var/spool/cron/crontabs/root - Íhor Mé

8

常见的定时任务通常存储在每个用户文件中,位于/var/spool/cron

最简单的方法可能是创建一个配置好的文本文件,然后将其复制到cron spool文件夹并确保它具有正确的权限(600)。


32
直接修改/var/spool/cron中的文件是不被赞同的。实际上,如果你查看那里的文件,它们通常会包含诸如“请勿编辑此文件”之类的警告作为第一行。 - Jared
14
@Jared,我非常赞同这个想法,但是说“它被看作不好的”并没有太大帮助。相反,应该说明应该编辑哪个其他文件(如果有的话),或者解释手动编辑文件的风险。我打算通过自动命令行创建一些cron作业,如果编辑这个文件既是唯一的选择,又没有重大副作用,我不明白为什么我不应该使用它。 - Balmipour
62
從英文翻譯成中文。僅返回翻譯後的文本:向下滾動以查看真正答案。 - John Red
1
在我看来,这个答案更好:https://dev59.com/MnRB5IYBdhLWcg3weXOX#610860 - galaux
2
我采用了这种方法,但后悔了。在RHEL上,目录/var/spool/cron不是全局可执行的,因此用户无法遍历该目录并手动编辑其文件。如果您使/var/spool/cron全局可执行,您友好的本地系统管理员会对您生气,而且如果cronie软件包被重新安装或更新,则权限更改可能会被覆盖。 - ellipse-of-uncertainty
@Jared,这些警告通常是因为服务器上有类似cpanel或plesk的东西,这些可能会在某个时候覆盖cron文件。感谢您在过去4年中学到了这一点! - Don

7
作为对那些建议使用"crontab -l | crontab -"的人的纠正:这种方法并不适用于所有系统。比如说,我需要在几十台运行旧版本SUSE(不要问为什么)的服务器上添加根crontab任务。旧版本的SUSE在"crontab -l"的输出中添加了注释行,使得"crontab -l | crontab -"不是幂等的(Debian在crontab手册中认识到了这个问题,并修补了它的Vixie Cron版本以更改"crontab -l"的默认行为)。
在"crontab -l"添加注释的系统上以编程方式编辑crontab,您可以尝试以下方法: "EDITOR = cat crontab -e> old_crontab; cat old_crontab new_job | crontab -" "EDITOR = cat"告诉crontab使用cat作为编辑器(而不是通常的默认vi),它不会更改文件,而是将其复制到stdout。如果"crontab -"期望的输入格式与"crontab -e"的输出不同,则仍可能失败。不要尝试将最终的"crontab -"替换为"crontab -e",这样做无效。

6

好的,/etc/crontab只是一个ASCII文件,因此最简单的方法就是:

 echo "*/15 * * * *   root     date" >> /etc/crontab

这将添加一个工作,每15分钟给您发送电子邮件。根据需要进行调整,并通过grep或其他方式进行测试,以确定该行是否已添加,使您的脚本具有幂等性。

在Ubuntu等操作系统中,您还可以将文件放入/etc/cron.*中,这样更易于进行测试,而且不会干扰(系统)配置文件,如/etc/crontab


1
在技术上,我认为不需要使用 crond 监视 crontab 的更改,即使在现实中大多数实现都这样做了,因此我建议之后调用 crontab -e 来激活它。如果我的记忆没有出错,crontab -e 会尊重 EDITOR 变量的设置,因此将其设置为 /bin/true 只需要强制重新读取 crontab。 - Ulrich Schwarz
1
在任何最近的Linux系统上,“crond”确实会监视,而且在OP所述的平台上也是如此。 - Dirk Eddelbuettel
只有当您是root用户并且希望脚本以root身份运行时,才需要这样做。在OP的情况下可能不是理想的选择。 - Keith
并非如此,在/etc/crontab中我有大量非root条目。你只需要使用sudo来追加到文件中。无论如何,就像我所说的,还有/etc/cron.*,但是你也需要成为root才能在那里写入。 - Dirk Eddelbuettel

3

这是一种逐步添加cron作业的方法:

  ssh USER_NAME@$PRODUCT_IP nohup "echo '*/2 * * * * ping -c2 PRODUCT_NAME.com >> /var/www/html/test.html' | crontab -u USER_NAME -"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接