如何通过程序创建新的cron任务?

153

我希望能够以编程的方式添加一个新的cron任务,最好的方法是什么?

我的研究来看,似乎我可以先将当前的crontab导出,然后附加一个新的,再将其输入到crontab中:

(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -

有更好的方法吗?


3
你的解决方案看起来不错。 - Craig S
在Solaris上,只需删除最后一个crontab的破折号即可。您可以添加grep以避免添加已存在的行。 - lacroix1547
可能是 如何使用Bash创建cron作业 的重复问题。 - Ciro Santilli OurBigBook.com
使用花括号代替圆括号可以避免生成新的进程。请确保在花括号周围保留空格,{ ... ; }。 - Jay Winston
@davidmytton - 你会考虑将你的选定答案改为MarkR的答案吗?我认为共识是这是更好的答案,对于其他人来说,它将改善这个stackoverflow条目。 - Reinsbrain
我想知道是否有更新的Linux调度系统(如anacron)支持这个需求。 - Sridhar Sarnobat
21个回答

165

如果您以root身份运行,最好的方法是将文件放到/etc/cron.d目录下。

如果您使用软件包管理器打包软件,则可以在该目录中放置文件,它们会被解释为类似于cron表,但带有额外的用户名字段,例如:

文件名:/etc/cron.d/per_minute

内容:* * * * * root /bin/sh /home/root/script.sh


6
请确保所使用的 cron 版本支持 /etc/cron.d/ 目录。大多数现代 Linux 发行版都支持该功能。 - sleske
14
这可能存在一个潜在的注意点,即 cron 每小时只会检查一次该文件夹中的新添加内容。如果你希望作业立即开始运行,请注意这一点。 - JonathanK
8
@JonathanK,你知道cron是否可以被要求重新扫描/etc/cron.d/*吗?如果需要等一个小时才能检查,那么很难知道某个东西是否有效! - halfer
1
至少在CentOS和RHEL上,“cron守护程序每分钟检查/etc/crontab文件,/etc/cron.d/目录和/var/spool/cron/目录是否有任何更改。” https://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-autotasks-cron-configuring.html https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/5/html/Deployment_Guide/ch-autotasks.html - dskrvk
4
这个文件应该如何设置权限?是通过运行命令 chmod +x /etc/cron.d/per_minute 实现的吗? - giò
显示剩余4条评论

118

OP的解决方案存在一个bug,可能会导致条目被添加两次,使用以下方法修复。

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -

5
这实际上是一个更好的解决方案,如果未被描述的话。它确保命令不会被添加两次到crontab中。 - Bufke
7
为确保唯一性,只需在 uniq 之前对内容进行排序,例如:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab - - mway
9
无需使用 uniq 命令。可以在 sort 命令上使用 -u 选项来实现相同的功能。 - papiro
3
这里存在一个(小但危险的)竞态条件。 - ron rothman
8
如何避免在首次编辑crontab时出现“用户没有定时任务(no crontab for user)”的问题。 - wyx
显示剩余7条评论

31

要将某物添加到cron中

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -

要从cron中删除此内容

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | grep -v hupChannel.sh |  sort | uniq | crontab -

希望能对某人有所帮助


1
这正是我正在寻找的。 我只想添加这个:| grep -v '^#' | 以过滤掉注释。 - Tjunkie
7
е®һйҷ…дёҠжӮЁдёҚйңҖиҰҒдҪҝз”Ё2>&1 | grep -v "no crontab"пјҢеӣ дёәеҪ“жІЎжңүcrontabж—¶пјҢиҫ“еҮәиЎҢвҖңcrontab: no crontab for...вҖқдјҡиў«еҸ‘йҖҒеҲ°stderrгҖӮ жІЎжңүеҝ…иҰҒжҚ•иҺ·иҜҘиҫ“еҮә并е°Ҷе…¶еҸ‘йҖҒеҲ°stdoutпјҢ然еҗҺеҶҚдҪҝз”ЁgrepиҝҮж»Өе®ғгҖӮ еҰӮжһңжӮЁзҡ„зӣ®ж ҮжҳҜйҒҝе…ҚеңЁиҫ“еҮәдёӯзңӢеҲ°вҖңcrontabпјҡno crontab for...вҖқпјҢеҲҷеҸҜд»ҘдҪҝз”Ё2> /dev/null | sort....гҖӮ - matty

11

这里大多数解决方案都是添加到crontab的行。如果您需要更多控制权,则需要能够控制整个crontab的内容。

您可以使用管道来实现这一点。

要完全重写crontab,请执行

echo "2 2 2 2 2 /bin/echo foobar" |crontab -

这应该很容易与其他在此描述的答案结合起来,例如

crontab -l | <something> | tee |crontab -

或者,如果您将内容存储在文件中,则更加简单

cat <file> |crontab -

6

只需将编辑器更改为tee命令:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e

11
请注意 - 这将清除任何现有的条目。 - starfry

6
如果您计划只运行一次,仅使用wget下载某些内容,请查看“at”命令:'at'

5
假设您的crontab中已经有一个条目,以下命令应该相对有效。请注意,$CMD变量只是为了可读性而存在。在过滤重复项之前进行排序很重要,因为uniq仅适用于相邻行。
CMD='wget -O - -q http://www.example.com/cron.php"'
(crontab -l ; echo "0 * * * * $CMD") | sort | uniq | crontab -

如果你当前的crontab为空,你将会收到以下错误信息:stderr。
no crontab for user

如果你想避免这种情况,可以增加一些复杂性,做如下操作:
(crontab -l ; echo "0 * * * * $CMD") 2>&1 | sed "s/no crontab for $(whoami)//"  | sort | uniq | crontab -

5
这是另一种避免重复的单行方法。
(crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -

这里有一种方法可以实现JohnZ的答案并避免“用户没有crontab”消息,或者如果您需要在set -eu类型的环境中操作并且不能让任何东西返回失败(此时2>/dev/null部分是可选的):
( (crontab -l 2>/dev/null || echo "")  ; echo "0 * * * * your_command") | sort -u - | crontab -

如果你想将事物分开以便更易读:
new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
(echo "$preceding_cron_jobs" ; echo "$new_job") | sort - | uniq - | crontab -

或者选择删除对your_command的所有引用(例如,如果计划已更改,您只希望它被定时一次)。在这种情况下,我们不再需要uniq(额外的好处是插入顺序也得到保留):
new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
preceding_cron_jobs=$(echo "$preceding_cron_jobs" | grep -v your_command )
(echo "$preceding_cron_jobs" ; echo "$new_job") | crontab -

4

man crontab is also useful:

CRONTAB(1)

NAME

   crontab - manipulate per-user crontabs (Dillon's Cron)

概述

   crontab file [-u user] - replace crontab from file

   crontab - [-u user] - replace crontab from stdin

   crontab -l [user] - list crontab for user

4
“replace crontab from stdin”的部分实际上只是一半的答案 :-) - Grodriguez

2
function cronjob_exists($command){

    $cronjob_exists=false;

    exec('crontab -l', $crontab);


    if(isset($crontab)&&is_array($crontab)){

        $crontab = array_flip($crontab);

        if(isset($crontab[$command])){

            $cronjob_exists=true;

        }

    }
    return $cronjob_exists;
}

function append_cronjob($command){

    if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){

        //add job to crontab
        exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);


    }

    return $output;
}

    append_cronjob('* * * * * curl -s http://localhost/cron/test.php');

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