如何以编程方式创建新的 cron 作业?

我希望能够通过编程添加一个新的 cron 作业,什么是最好的方法来做到这一点?

我的研究中,我似乎可以转储当前的 crontab,然后附加一个新的 crontab,通过管道将其返回到 crontab:

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

还有更好的办法吗?

84571 次浏览

您还可以直接编辑 cron 表文本文件,但是您的解决方案似乎是完全可以接受的。

如果您以 root 身份运行,最好的方法是将一个文件放入/etc/cron.d 中

如果你使用软件包管理器来打包你的软件,你可以简单地把文件放在那个目录下,它们被解释为 crontab,但是用户名有一个额外的字段,例如:

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

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

这招对我一直很管用。

您应该考虑一个稍微复杂一点的脚本,它可以做三件事情。

  1. 附加 crontab 行; 确保它不存在。在它已经存在的时候添加是不好的。

  2. 删除 crontab 行,如果它不存在,可能只会发出警告。

  3. 以上两个特性的组合来替换 crontab 行。

如果您计划为了获得某些东西而进行一次性运行,那么可以看一下

还可以将任务添加到/etc/cron. */

Man crontab 也很有用:

CRONTAB (1)

姓名

   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

OP 的解决方案有一个错误,它可能允许条目被添加两次,使用下面的修复。

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

假设您的 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 -

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

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e
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');

向 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 -

希望能帮助别人

对于 JohnZ 的回答,如果您是 sudoer 用户,下面是作为 root 用户调度的语法:

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

这将在添加命令之前进行检查,以确保命令不存在。

crontab -l 2>/dev/null | grep -q '/path/to/script' || echo "5 * * * * /path/to/script" | crontab -

干杯。

将 stdout 管道化到 crontab中并没有在 macOS 上为我安装新的 crontab,所以我在一个子 shell 中使用 tee编辑器找到了这个解决方案:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)

这里有另一个一行程序的方法,可以避免重复

(crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -

这里有一种方法可以做 JohnZ 的回答,避免 no crontab for user消息,或者如果你需要在 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 的任何引用(例如: 如果计划已经更改,那么您只希望它被 cron 一次)。在这种情况下,我们不再需要 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 -

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

您可以使用管道来非常优雅地完成这项工作。

要完全重写 crontab,请执行

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

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

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

或者,如果文件中有内容,则更简单

cat <file> |crontab -

如果希望任务以用户身份运行:

crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | crontab -

如果希望任务以特权运行:

sudo crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | sudo crontab -

检查任务(有或没有“ sudo”) :

crontab -l | sed '/^$/d; /#/d'

下面是我在脚本中使用的内容

1.

(2>/dev/null crontab -l ; echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -
cat <(crontab -l 2>/dev/null) <(echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -

# 写出当前的 crontab

crontab -l > mycron 2>/dev/null

# echo new cron into cron file

echo "0 3 * * * /usr/local/bin/certbot-auto renew" >> mycron

# install new cron file

crontab mycron


rm mycron

为了在将来更改命令时具有灵活性,您可以这样做(最好使用更新脚本)

MARK=SOME_UNIQUE_MARK_TEXT
LINE="This is the command # $MARK"
# NOTE: I'm using -e because I might want to avoid weird bash expansions for '*' or '$' and place:
# \x2A instead of *
# \x24 instead of $
( crontab -l | grep -v $MARK ; echo -e "0 * * * *" $LINE ) | crontab -

通过这种方式,我可以更新一个旧的 crontab 命令,它不再服务于当前目的。

基本上,我得到了当前的 crontab,我删除了包含 MARK (grep -v)的行,并通过 echo -e在 crontab 文件的末尾添加新的代码来替换它。在这个特殊的情况下,我希望它在每小时0分钟执行 0 * * * *,因为它可以从 给你看到。