我希望能够通过编程添加一个新的 cron 作业,什么是最好的方法来做到这一点?
从 我的研究中,我似乎可以转储当前的 crontab,然后附加一个新的 crontab,通过管道将其返回到 crontab:
(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -
还有更好的办法吗?
您还可以直接编辑 cron 表文本文件,但是您的解决方案似乎是完全可以接受的。
如果您以 root 身份运行,最好的方法是将一个文件放入/etc/cron.d 中
如果你使用软件包管理器来打包你的软件,你可以简单地把文件放在那个目录下,它们被解释为 crontab,但是用户名有一个额外的字段,例如:
文件名: /etc/cron.d/per_minute
/etc/cron.d/per_minute
内容: * * * * * root /bin/sh /home/root/script.sh
* * * * * root /bin/sh /home/root/script.sh
这招对我一直很管用。
您应该考虑一个稍微复杂一点的脚本,它可以做三件事情。
附加 crontab 行; 确保它不存在。在它已经存在的时候添加是不好的。
删除 crontab 行,如果它不存在,可能只会发出警告。
以上两个特性的组合来替换 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
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编辑器找到了这个解决方案:
crontab
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部分是可选的) :
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 * * * *,因为它可以从 给你看到。
grep -v
echo -e
0 * * * *