bash 检查重复的 cron 作业

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17598135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:53:50  来源:igfitidea点击:

Checking for duplicate cron jobs

bashcroncrontab

提问by Paul Mennega

We are deploying code to our application server environment, and part of that process is creating a number of cron jobs on the server. When code gets pushed, our deployment script creates the required cron jobs without a problem using the following:

我们正在将代码部署到我们的应用程序服务器环境中,该过程的一部分是在服务器上创建许多 cron 作业。当代码被推送时,我们的部署脚本使用以下命令创建所需的 cron 作业,没有问题:

CRON_FILE=$SCRIPT_DIR/cron.txt 
if [[ ! -f "$CRON_FILE" ]]; then
        printf "Cron template file missing!\n\n"
        exit 1
fi
while read LINE || [[ -n "$LINE" ]]; do
        printf "\n> Adding cron job \"$LINE\"\n"
        crontab -l | { cat; echo "$LINE"; } | crontab -
done < $CRON_FILE

The issue is that after the initial deployment, additional deployments are creating duplicate cron jobs.

问题是在初始部署之后,额外的部署会创建重复的 cron 作业。

Any pointers on how to detect if a cron job already exists?

有关如何检测 cron 作业是否已存在的任何指示?

回答by janos

When you add your cron job, include a comment with a unique label. Later you can use that unique label to determine if the cron job exists or not, and also to "uninstall" the cron job.

添加 cron 作业时,请添加带有唯一标签的注释。稍后您可以使用该唯一标签来确定 cron 作业是否存在,以及“卸载”cron 作业。

I do this all the time. I have a reusable script for this:

我一直这样做。我有一个可重用的脚本:

#!/bin/sh
#
# Usage: 
# 1. Put this script somewhere in your project
# 2. Edit "
0 0 * * * echo hello world
0 0 * * * date
".crontab file, it should look like this, # but without the # in front of the lines #0 * * * * stuff_you_want_to_do #15 */5 * * * stuff_you_want_to_do #* * 1,2 * * and_so_on # 3. To install the crontab, simply run the script # 4. To remove the crontab, run ./crontab.sh --remove # cd $(dirname "
crontab -l | grep 'match-your-cronjob-search' || (crontab -l 2>/dev/null; echo "* * * * * /bin/cronjobCommandYouWant >> /dev/null 2>&1") | crontab -
") test "" = --remove && mode=remove || mode=add cron_unique_label="# $PWD" crontab="
    CRON_FILE=$SCRIPT_DIR/cron.txt 
if [[ ! -f "$CRON_FILE" ]]; then
        printf "Cron template file missing!\n\n"
        exit 1
fi
while read LINE || [[ -n "$LINE" ]]; do
        printf "\n> Adding cron job \"$LINE\"\n"
        crontab -l | grep "$LINE" || (crontab -l 2>/dev/null; echo "$LINE") | crontab -
done < $CRON_FILE
".crontab crontab_bak=$crontab.bak test -f $crontab || cp $crontab.sample $crontab crontab_exists() { crontab -l 2>/dev/null | grep -x "$cron_unique_label" >/dev/null 2>/dev/null } # if crontab is executable if type crontab >/dev/null 2>/dev/null; then if test $mode = add; then if ! crontab_exists; then crontab -l > $crontab_bak echo 'Appending to crontab:' cat $crontab crontab -l 2>/dev/null | { cat; echo; echo $cron_unique_label; cat $crontab; echo; } | crontab - else echo 'Crontab entry already exists, skipping ...' echo fi echo "To remove previously added crontab entry, run:
int fd = open('/tmp/1.txt', O_CREAT|O_EXCL)
if (fd === -1) {
   print "job exist"
   exit(1)
}
//unlink()
// your code
--remove" echo elif test $mode = remove; then if crontab_exists; then echo Removing crontab entry ... crontab -l 2>/dev/null | sed -e "\?^$cron_unique_label$?,/^$/ d" | crontab - else echo Crontab entry does not exist, nothing to do. fi fi fi

Save the script as crontab.shin your project directory, and create a crontab.sh.crontabwith your cron job definitions, for example:

将脚本保存crontab.sh在您的项目目录中,并crontab.sh.crontab使用您的 cron 作业定义创建一个,例如:

const fs = require('fs')
try {
const fd = fs.openSync('/tmp/1.txt', 'wx')
} catch(err) {
  console.log('job exist')
  process.exit(0)
}

fs.unlinkSync('/tmp/1.txt')
fs.appendFileSync(fd, 'pid', 'utf8');
  • To install your cron jobs, simply run ./crontab.sh
  • The script is safe to run multiple times: it will detect if the unique label already exists and skip adding your cron jobs again
  • To uninstall the cron jobs, run ./crontab.sh --remove
  • 要安装您的 cron 作业,只需运行 ./crontab.sh
  • 该脚本可以安全运行多次:它会检测唯一标签是否已经存在并再次跳过添加您的 cron 作业
  • 要卸载 cron 作业,请运行 ./crontab.sh --remove

I put this on GitHub too: https://github.com/janosgyerik/crontab-script

我也把它放在 GitHub 上:https: //github.com/janosgyerik/crontab-script

Explanation of sed -e "\?^$cron_unique_label\$?,/^\$/ d":

的解释sed -e "\?^$cron_unique_label\$?,/^\$/ d"

  • In its simplest form the expression is basically: sed -e '/start/,/end/ d'
  • It means: delete the content between the lines matching the start pattern and the end pattern, including the lines containing the patterns
  • The script quotes the sedcommand with double-quotes instead of single quotes, because it needs to expand the value of the $cron_unique_labelshell variable
  • The start pattern \?^$cron_unique_label\$?uses a pair of ?instead of /to enclose the pattern, because $cron_unique_labelcontains /, which would cause problems
  • The starting ?must be escaped with a backslash, but to be honest I don't know why.
  • The ^matches start of the line and $end of the line, and the $must be escaped, otherwise the shell would expand the value of the $?shell variable
  • The end pattern /^\$/is relatively simple, it matches a start of line followed by end of line, in other words an empty line, and again the $must be escaped
  • The dat the end is the sedcommand, to delete the matched lines, effectively removing it from the content of crontab -l, which we can pipe to crontab -
  • 最简单的表达式基本上是: sed -e '/start/,/end/ d'
  • 意思是:删除匹配开始模式和结束模式的行之间的内容,包括包含模式的行
  • 脚本sed用双引号而不是单引号引用命令,因为它需要扩展$cron_unique_labelshell变量的值
  • 开始模式\?^$cron_unique_label\$?使用一对?代替/来包围模式,因为$cron_unique_labelcontains /,这会导致问题
  • 开头?必须用反斜杠转义,但老实说我不知道​​为什么。
  • ^场比赛开始线与$线的末端,而$必须转义,否则外壳将扩大的价值$?shell变量
  • 结束模式/^\$/相对简单,它匹配行首和行尾,即空行,并且$必须再次转义
  • 所述d在端部是sed命令,删除该匹配线,有效地从内容删除它crontab -l,我们可以通过管道到crontab -

回答by Ligemer

Weird, but very thorough answers. IMO overly complex.

奇怪,但非常彻底的答案。IMO 过于复杂。

Here's a decent one liner for anyone coming to this for a 2017 answer:

对于 2017 年回答此问题的任何人来说,这是一个不错的衬里:

#!/bin/sh
#
# Usage:
# 1. Put this script somewhere in your project
# 2. Edit "".crontab file, it should look like this,
#    but without the # in front of the lines
#0  *   *   *   *   stuff_you_want_to_do
#15 */5 *   *   *   stuff_you_want_to_do
#*  *   1,2 *   *   and_so_on
# 3. To install the crontab, run ./crontab.sh <nameOfCronTabfile>
# 4. To remove the crontab, run ./crontab.sh <nameOfCronTabfile> --remove

cd $(dirname "
crontab -l 2>/dev/null | { cat; echo; echo $cron_unique_label; cat $crontab; echo "# cm #"; } | crontab -
") test "" = --remove && mode=remove || mode=add cron_unique_label="# cmID:$PWD|#" crontab="".crontab crontab_bak=$crontab.bak test -f $crontab || cp $crontab.sample $crontab crontab_exists() { crontab -l 2>/dev/null | grep -x "$cron_unique_label" >/dev/null 2>/dev/null } # if crontab is executable if type crontab >/dev/null 2>/dev/null; then if test $mode = add; then if ! crontab_exists; then crontab -l > $crontab_bak echo 'Appending to crontab:' echo '-----------------------------------------------' cat $crontab crontab -l 2>/dev/null | { cat; echo; echo $cron_unique_label; cat $crontab; echo "# cm #"; } | crontab - else echo 'Crontab entry already exists, skipping ...' echo fi echo '-----------------------------------------------' echo "To remove previously added crontab entry, run:
crontab -l 2>/dev/null | sed -e "\?^$cron_unique_label$?,/^# cm #$/ d" | crontab -
--remove" echo elif test $mode = remove; then if crontab_exists; then echo 'Removing crontab entry ...' crontab -l 2>/dev/null | sed -e "\?^$cron_unique_label$?,/^# cm #$/ d" | crontab - else echo 'Crontab entry does not exist, nothing to do.' fi fi fi

Works great for us to not have dupe crons.

对我们来说没有欺骗的 crons 非常有用。

And here's the edited script from the original poster:

这是来自原始海报的编辑脚本:

##代码##

回答by grant sun

We can also do it in code: first in bash, check the manual: man 2 open:

我们也可以在代码中进行:首先在bash中,查看手册:man 2 open:

##代码##

Js version:

JS版本:

##代码##

回答by LJay

Your script janos is awesome, works perfectly and was exactly what i was looking for with one little glitch. I couldnt manage multiple xxx.crontab templates. Your script worked fine and i added it to my bootstrapping routines with a little modification so i can pass a first parameter $1 of the xx.crontab filename and second parameter $2 can be the removal. I have parent shell scripts which then conditional decide, which, all or combination of crontab files i want to add/remove.

你的脚本 janos 很棒,工作完美,正是我正在寻找的一个小故障。我无法管理多个 xxx.crontab 模板。您的脚本运行良好,我将它添加到我的引导程序中,并稍作修改,这样我就可以传递 xx.crontab 文件名的第一个参数 $1,第二个参数 $2 可以删除。我有父 shell 脚本,然后有条件地决定要添加/删除哪些、所有或组合的 crontab 文件。

Here the script with my modifications included:

这里包含我修改的脚本:

##代码##

UPDATE:Sry, didnt noticed the weak empty line pattern for removing a crontab. Simply would delete everything after the found crontab id, including manually added crontabs. Changed the empty line end pattern to a little end tag. So it will add crontabs with:

更新:Sry,没有注意到用于删除 crontab 的弱空行模式。只需删除找到的 crontab id 之后的所有内容,包括手动添加的 crontab。将空行结束模式更改为一个小结束标记。所以它会添加 crontabs:

##代码##

.. and removing exactly only this cron with:

.. 并仅删除此 cron:

##代码##