以编程方式(通过ssh)向crontab添加一些内容


13

我有一个部署脚本,它必须向用户添加一些内容crontab(触发一个脚本,该脚本每XXX天清除一次日志),但这只能在第一次部署期间或需要更新时执行。

(我可以跑步xxx.py deploy envxxx.py update env

所以我必须这样做:

Check if my cronJob already exist
Put my cronJob if it does not already exist
or
update my cronjob if one of the parameter of the command is different

我看不到如何在crontab不使用crontab -e或编辑crontab文件的情况下向其中添加/检查/删除内容(下载,重写,重新上传)

PS:这是一个特定于用户的cronjob,“ webadmin”将执行此操作,并且他不应使用sudo进行操作。


1
是否必须在特定于用户的crontab中?大多数预先打包的cron作业都进入/etc/cron.*目录之一。
CVn

CentOS有/etc/cron.d吗?如果是这样,请使用您的应用程序
专有

是的,它是特定于用户的。我不能将其添加到/etc/cron.d中,因为它是一个根文件,因此内部仅允许root的工作(我可以sudo,但有人告诉我这是一个不好的做法)
slides_alpha

1
与相同/etc/crontab/etc/cron.d/时间表中的文件会在排定规范后立即包含一个用于用户名的额外字段。例如* * * * * username /path/to/script。查看man 5 crontab并搜索SYSTEM CRON
cas

Answers:


15

到目前为止我最好的主意

首先检查内容是否匹配其中的内容,如果不匹配则仅更新:

if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q 'some_command'; echo $?) == 1 ]]
then
    echo $(crontab -l ; echo '* 1 * * * some_command') | crontab -
fi

但这变得足够复杂,无法围绕该cron任务构建单独的脚本。

其他想法

您可以通过stdin将字符串发送到crontab(请注意,这会清除以前的crontab条目):

echo "* 1 * * * some_command" | crontab -

这甚至应该可以通过ssh正常运行:

echo "* 1 * * * some_command" | ssh user@host "crontab -"

如果要附加到文件,可以使用以下命令:

# on the machine itself
echo "$(echo '* 1 * * * some_command' ; crontab -l)" | crontab -
# via ssh
echo "$(echo '* 1 * * * some_command' ; ssh user@host crontab -l)" | ssh user@host "crontab -"

这取决于:您需要那里的东西吗?:)
菲利普-Zyan K Lee- Stockmann

awww ...不是以root身份运行?...我将其重写...
菲利普-Zyan K Lee- Stockmann

eh,我喜欢:D
slides_alpha

此解决方案有两个问题:1)echo '*...将扩展*到文件列表。2)crontab中的行结尾已删除。
Heath Raftery

我可以通过以下方法解决这些问题:1)更改为echo "*...2)echo $从行的开头删除。
Heath Raftery

3

为了记录,我建议使用/etc/cron.d/。只有root用户可以在此处写入文件,但条目可以任何用户身份运行(不需要sudo)。

echo '0 0 * * 0 webadmin /usr/local/bin/tidy_logfiles' > ~/webadmin.cron
scp -p ~/webadmin.cron root@remote_host:/etc/cron.d/webadmin

这可以多次应用,webadmin.cron并在复制之前根据需要更新本地文件。

您甚至可以删除配置:

ssh -q root@remote_host rm -f /etc/cron.d/webadmin

请注意,在许多情况下,您无法为scp/ ssh命令提供root用户的密码。相反,您需要设置公用/专用密钥证书。同样,通过暗示,本地帐户(无论它是什么)将具有对远程服务器的完全root访问权限。目前尚不清楚这是否适合您的特定情况。


这是我的客户端服务器,我不能以root用户身份登录,但是可以将它sudo到其中,如果这样做,它们会杀死我。这是一个webadlmin的工作,因此只能放在webadmin中,这就是sysadmin告诉我的。
slides_alpha

@sliders_alpha作业仅以网络管理员身份运行。这是需要根等效的配置。但是,我也会寻找非根解决方案。
roaima

1
+1。/etc/cron.d/正是出于这个目的而存在-以便程序包/部署可以在此处放置crontab文件。
cas

3

我强烈建议为此使用Ansible *,而不要自己动手。还是Puppet或Chef,但是Ansible非常适合于此类零基础架构部署脚本。

这是因为已经有用于解决此类问题的模块,并且配置管理工具已将幂等性作为基本设计目标—这是仅在需要时更改的属性,即使您不小心(或有意)再次运行它也是如此。

特别是,Ansible的cron模块可以修改用户crontab。另外,如果您以后想要调整以使用系统crontab,这将是一个非常容易的调整,而不是重写。


*免责声明:我为Red Hat工作,Ansible是Red Hat赞助的项目。


是的,问题是,我两个月前不了解ansible,现在我们有了一个庞大的python部署脚本(但是他是宏伟的,可读的,可维护的;;))下一次,我将使用ansible但现在开始回来是不可能的(钱钱钱)
–sliders_alpha

1

如果要通过目标帐户添加Cron作业,请运行crontab -e。此命令通过编辑器传递crontab。告诉它使用可以根据需要修改crontab的编辑器命令。编辑器命令作为带有附加临时文件名的shell片段执行。

unset VISUAL
EDITOR='update_crontab () {
  set -e
  new=$(mktemp)
  if <"$1" grep -v "^#" | grep -w do_stuff; then
    # Remove existing entries containing do_stuff
    grep -v -w do_stuff "$1" >"$new"
  else
    cp "$1" "$new"
  fi
  # Add the new entry
  echo "1 2 3 4 5 do_stuff --new-options" >>"$new"
  mv "$new" "$1"
}
update_crontab' crontab -e

这种方法比本地方法更可靠,crontab -l | … | crontab -因为如果同时编辑crontab,则该方法很容易受到竞争条件的影响:对crontab -l和的调用之间的修改crontab -将被撤消。


1

这是@ phillip-zyan-k-lee-stockmann提供的内容的改编,基于他的“迄今为止最好的想法”代码。

我从他(出色且有用的摘要)中所做的更改基本上是:

  • 正则表达式不仅用于命令名称,还用于包括时间字符串在内的整个条目。这样,即使其他条目中存在相同名称或重叠名称的命令,它也可以支持添加命令。(它仍然不会按相同的时间表两次添加相同的命令。)
  • 一点日志
  • 由于种种原因,我将(并命名为)我的时间改为每小时一次。易于根据crontab语法进行调整

这是我所谓的代码crontab-add-hourly.sh

#!/bin/bash

# PURPOSE:
# To allow simple, programmatic addition of commands/entries into the crontab (if not already present)

cmd=$1
entry="0 * * * * $cmd"
printf "we want to add this entry:\n$entry\n\n" 
escapedEntry=$(printf '%s\n' "$entry" | sed 's:[][\/.^$*]:\\&:g') #from: https://unix.stackexchange.com/a/129063/320236
printf "but first we'll see if it's already in there using this regex pattern:\n$escapedEntry\n\n"

if [[ $(crontab -l | egrep -v '^(#|$)' | grep -q "$escapedEntry"; echo $?) == 1 ]] # from: https://unix.stackexchange.com/a/297377/320236
then
    printf "all clear; pattern was not already present; adding command to crontab hourly:\n$cmd\n\n"
    (crontab -l ; printf "$entry\n\n") | crontab -
else
    printf "pattern already present; no action taken\n\n"
fi

用法示例和输出:

$ ./crontab-add-hourly.sh my-script.bash

we want to add this entry:
0 * * * * my-script.bash

but first we'll see if it's already in there using this regex pattern:
0 \* \* \* \* my-script\.bash

all clear; pattern was not already present; adding command to crontab hourly:
my-script.bash

0

TL; DR:这确实有效,在Bash 4.4中进行了测试。

if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q 'some_command'; echo $?) == 1 ]]
then
    set -f
    printf "$(crontab -l ; echo '* * * * * some_command')\n" | crontab -
    set +f
fi

如@Phillip -Zyan K Lee-Stockmann答复的注释中所述,该解决方案扩展*到当前目录中的所有文件。我无法收到评论的建议。set -f禁用通配符扩展,请参阅https://stackoverflow.com/a/11456496/915441

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.