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

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

我有一个部署脚本。它必须向用户添加一些内容crontab (触发一个脚本来清理日志XXX天);但是,只能在首次部署期间或需要更新时执行此操作。

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

所以我需要这样做:

检查我的 cronJob 是否已存在
如果我的 cronJob 尚不存在,则提交它; 如果命令的参数之一不同,
则更新我的 cronJob

我不知道如何在crontab 不使用crontab -e或“手动”编辑crontab文件的情况下添加/检查/删除某些内容(下载、重写、重新上传)。

PS:这是一个用户特定的 cronjob; “webadmin”将执行此操作,但他不应该用来sudo执行此操作。

答案1

到目前为止我最好的主意

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

if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q 'some_command'; echo $?) == 1 ]]
then
    set -f
    echo $(crontab -l ; echo '* 1 * * * some_command') | crontab -
    set +f
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 2>&1)" | crontab -
# via ssh
echo "$(echo '* 1 * * * some_command' ; ssh user@host crontab -l 2>&1)" | ssh user@host "crontab -"

答案2

作为记录,我建议使用/etc/cron.d/.只有 root 可以在此处写入文件,但条目可以配置为以任何用户身份运行(无需sudo在运行时)。此示例定义了名为的任务,该任务将在每周日午夜以用户身份my_webadmin执行:/usr/local/bin/tidy_logfileswebadmin

echo '0 0 * * 0 webadmin /usr/local/bin/tidy_logfiles' >/etc/cron.d/my_webadmin

一个重要的部分是,它my_webadmin对于您来说应该是唯一的(尽管对于运行来说不一定是唯一的),因为任何安装包也可以在此处写入文件,并且您希望避免冲突。有了这个唯一性约束,您可以my_webadmin通过简单的覆盖进行更新,因为您知道它是“您的”并且不会包含任何其他人/任何东西的条目。

此外,通过这种方法,删除 cron 条目变得微不足道

rm -f /etc/cron.d/my_webadmin

可能超出了您的问题范围,但如果您可以远程访问 root 帐户(或通过sudo),您甚至可以远程配置,

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

或者,

echo '0 0 * * 0 webadmin /usr/local/bin/tidy_logfiles' |
    ssh -q root@remote_host 'cat >/etc/cron.d/my_webadmin'

并删除配置,

ssh -nq root@remote_host rm -f /etc/cron.d/my_webadmin

scp(请注意,在许多情况下,您无法为/命令提供 root 的密码,ssh因为 root 帐户受到限制以防止基于密码的登录。相反,您需要设置公钥/私钥证书。此外,暗示本地帐户(无论什么)它是)将拥有对远程服务器的完全root访问权限。)

答案3

我强烈建议使用 Ansible* 来实现此目的,而不是自己动手。或者 Puppet 或 Chef — 但 Ansible 非常适合像这样的零基础设施部署脚本。

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

特别是 Ansible 的计划任务模块可以修改用户的crontab。作为奖励,如果您想稍后调整以使用系统 crontab,这将是一个非常简单的调整而不是重写。


* 免责声明:我在红帽工作,Ansible 是红帽赞助的项目。

答案4

这是对什么的改编@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

相关内容