ChatGPT解决这个技术问题 Extra ChatGPT

如何在没有交互式编辑器的情况下使用 Bash 自动创建 cron 作业?

crontab 是否具有不使用编辑器创建 cron 作业的参数(crontab -e)。如果是这样,从 Bash 脚本创建 cronjob 的代码是什么?

可悲的是,这里的大多数最佳答案只是展示了如何修改 crontab——尽管是以相当安全的方式——但我认为这总体上是错误的方法。更好、更安全、更简单的方法是将文件放入 {{cron.d}} 中,并且(目前)有低票数的答案解释了如果您进一步向下看如何做到这一点。
谢谢@gregmac。在阅读了来自不同地方的示例并自己尝试之后,我添加了 this example
@gregmac 使用 /etc/cron.daily/ 和朋友似乎需要超级用户权限。

J
Jean-Luc Barat

您可以按如下方式添加到 crontab:

#write out current crontab
crontab -l > mycron
#echo new cron into cron file
echo "00 09 * * 1-5 echo hello" >> mycron
#install new cron file
crontab mycron
rm mycron

Cron 行解释

* * * * * "command to be executed"
- - - - -
| | | | |
| | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
| | | ------- Month (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)

来源 nixCraft


您应该使用 tempfile 或 mktemp
(crontab -l ; echo "00 09 * * 1-5 echo hello") | crontab -
(crontab -l ; echo "00 09 * * 1-5 echo hello") | crontab - - 更容易复制 Edo 的回答
如果 crontab -l 失败,我建议用 && 更改 ; 作为保护措施。所以,比如:(crontab -l && echo "0 0 0 0 0 some entry") | crontab -
@MacUsers,如果没有 crontab,crontab -l 会失败,因此使用 && 会使脚本无法将第一个条目添加到 crontab。
T
Thomas Weller

您也许可以即时进行

crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -

crontab -l 列出当前的 crontab 作业,cat 打印它,echo 打印新命令,crontab - 将所有打印的内容添加到 crontab 文件中。您可以通过执行新的 crontab -l 来查看效果。


对我来说是一种享受。如果用户没有现有的 crontab,您将看到 no crontab for <username>,但它仍然有效。
根据上面评论中的示例,猫没有理由
不适用于我的 Amazon EC2 实例。相反,(crontab -l ; echo "00 09 * * 1-5 echo hello") | crontab - 有效。
这看起来像是 UUcatA 的候选者。
您可能希望在最后一个命令之前通过“sort | uniq”管道,以避免在 crontab 中重复条目(虽然这可以更改行顺序)
M
MoonCactus

这个较短的文件不需要临时文件,它不受多次插入的影响,它允许您更改现有条目的时间表。

假设你有这些:

croncmd="/home/me/myfunction myargs > /home/me/myfunction.log 2>&1"
cronjob="0 */15 * * * $croncmd"

要将其添加到 crontab 中,且不重复:

( crontab -l | grep -v -F "$croncmd" ; echo "$cronjob" ) | crontab -

要将其从 crontab 中删除,无论其当前计划如何:

( crontab -l | grep -v -F "$croncmd" ) | crontab -

笔记:

grep -F 从字面上匹配字符串,因为我们不想将其解释为正则表达式

我们也忽略了时间调度,只寻找命令。这边走;可以更改计划,而无需向 crontab 添加新行的风险


如果 crontab 为空,我无法理解为什么您的脚本将不起作用。这只发生在我的 CI/CD 上的非交互式 shell 上:当直接从主机(交互式 shell)运行时,相同的脚本可以正常工作。
如果您的 bash 脚本有 set -e 并且 crontab 列表为空,则此命令将不起作用。发生这种情况是因为 crontab -l | grep -v -F "$croncmd"1 存在,因此会立即停止脚本。为避免这种情况,您可以以 ( crontab -l | grep -v -F "$COMMAND" || : ; echo "$JOB" ) | crontab - 的方式更新该行。如果 crontab 为空,|| : 将确保 grep 不会停止脚本。更多关于 : here
接得好。事实上,您也可以怯懦地只发出一个 crontab -e 以确保它预先存在;)
S
Stoutie

谢谢大家的帮助。拼凑我在这里和其他地方找到的东西,我想出了这个:

编码

command="php $INSTALL/indefero/scripts/gitcron.php"
job="0 0 * * 0 $command"
cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -

我无法弄清楚如何在不重复自己的情况下消除对这两个变量的需求。

command 显然是我要安排的命令。 job 采用 $command 并添加调度数据。我在完成工作的代码行中分别需要这两个变量。

细节

感谢duckyflip,我使用这个小重定向东西(<(*command*)) 将crontab -l 的输出转换为fgrep 命令的输入。然后 fgrep 过滤掉 $command(-v 选项)、不区分大小写(-i 选项)的任何匹配项。同样,小的重定向东西 (<(*command*)) 用于将结果转换回 cat 命令的输入。 cat 命令还通过使用重定向 thingy (<(*command*)) 再次接收 echo "$job"(自我解释)。因此,来自 crontab -l 的过滤输出和简单的 echo "$job" 组合在一起,通过管道 ('|') 传送到 crontab - 最终被写入。然后他们都过上了幸福的生活!

简而言之:

这行代码过滤掉任何与命令匹配的 cron 作业,然后用新的 cron 作业写出剩余的 cron 作业,有效地充当“添加”或“更新”功能。要使用它,您只需换出 commandjob 变量的值。


为了其他人阅读的好处,这种方法的优点是您可以多次运行它,而不必担心 crontab 中的重复条目(与所有其他解决方案不同)。这是因为 fgrep -v
如果您更喜欢传统的从左到右的管道方式,请将最后一行替换为:crontab -l | fgrep -i -v "$command" | { cat; echo "$job"; } | crontab -l
@AntoineLizée,你的回答最后有额外的“l”,它不应该在那里。
d
duckyflip

编辑(固定覆盖):

cat <(crontab -l) <(echo "1 2 3 4 5 scripty.sh") | crontab -

这将替换任何 crontab 内容
@TheBonsai 哦,我明白了,我现在修复了它,所以它应该将新命令附加到现有的 crontab 内容中
请记住,Bash 的进程替换会吞噬错误。如果 crontab -l 失败,但 crontab - 成功,您的 crontab 将是单行的。
M
Mike Mackintosh

关于 crontab 的使用已经有很多很好的答案,但没有提到更简单的方法,例如使用 cron

使用 cron 将利用位于 /etc/crontab/etc/cron.daily,weekly,hourly/etc/cron.d/ 的系统文件和目录:

cat > /etc/cron.d/<job> << EOF
SHELL=/bin/bash 
PATH=/sbin:/bin:/usr/sbin:/usr/bin 
MAILTO=root HOME=/  
01 * * * * <user> <command>
EOF

在上面的示例中,我们在 /etc/cron.d/ 中创建了一个文件,为命令成功执行提供了环境变量,并为命令提供了 user,以及 command 本身。此文件不应是可执行文件,并且名称应仅包含字母数字和连字符(下面有更多详细信息)。

不过,为了给出一个完整的答案,让我们看看 crontabcron/crond 之间的区别:

crontab -- maintain tables for driving cron for individual users

对于那些想要在系统上的用户上下文中运行作业的人来说,使用 crontab 可能非常有意义。

cron -- daemon to execute scheduled commands

对于那些使用配置管理或想为其他用户管理作业的人,在这种情况下我们应该使用 cron

手册页的快速摘录为您提供了一些关于该做什么和不该做什么的示例:

/etc/crontab 和 /etc/cron.d 中的文件必须由 root 拥有,并且不能是组可写或其他可写的。与假脱机区相比,/etc/cron.d 下的文件或 /etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly 和 /etc/cron.monthly 下的文件也可能是符号链接,前提是符号链接和它指向的文件都归 root 所有。 /etc/cron.d 下的文件不需要是可执行文件,而 /etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly 和 /etc/cron.monthly 下的文件可以,如它们由 run-parts 运行(有关更多信息,请参见 run-parts(8))。来源:http://manpages.ubuntu.com/manpages/trusty/man8/cron.8.html

从系统的角度来看,以这种方式管理 cron 更容易且更具可扩展性,但并不总是最好的解决方案。


值得一提的是,<job> 不应包含文件扩展名。
这似乎需要超级用户权限。有非超级用户等价物吗?
B
BradChesney79

因此,在 Debian、Ubuntu 和许多类似的基于 Debian 的发行版中......

有一个 cron 任务连接机制,它接受一个配置文件,将它们捆绑起来并将它们添加到运行的 cron 服务中。

您可以在 /etc/cron.d/somefilename 下放置一个文件,其中 somefilename 是您想要的任何内容。

sudo echo "0,15,30,45 * * * * ntpdate -u time.nist.gov" >> /etc/cron.d/vmclocksync

让我们分解一下:

sudo - 因为您需要提升权限才能更改 /etc 目录下的 cron 配置

echo - 在标准输出上创建输出的工具。 printf, cat ... 也可以

" - 在字符串的开头使用双引号,您是专业人士

0,15,30,45 * * * * - 标准 cron 运行计划,这个每 15 分钟运行一次

ntpdate -u time.nist.gov - 我要运行的实际命令

" - 因为我的第一个双引号需要一个伙伴来关闭正在输出的行

>> - 双重重定向追加而不是覆盖*

/etc/cron.d/vmclocksync - vmclocksync 是我选择的文件名,它位于 /etc/cron.d/

* 如果我们使用 > 重定向,我们可以保证我们只有一个任务条目。但是,我们可能会破坏现有文件中的任何其他规则。您可以自己决定是否使用 > 进行破坏是正确的,或者使用 >> 进行可能的重复是否适合您。或者,您可以做一些复杂或涉及的事情来检查文件名是否存在,是否有任何内容,以及是否添加了任何类型的重复项——但是,我有事情要做,我不能这样做你现在。


我有一个长时间运行的虚拟机,主机操作系统会进入睡眠状态——时间对虚拟机来说并不重要,但它会开始变得非常不正常,甚至不再是正确的一天。
谢谢!顺便说一句,sudo 不会影响重定向。请参阅 SC2024 和答案 stackoverflow.com/a/56283541/1121497
G
Gibbsoft

为了使用 BASH 脚本快速而肮脏地创建/替换 crontab,我使用了以下表示法:

crontab <<EOF
00 09 * * 1-5 echo hello
EOF

k
kvz

您可能正在自动执行此操作,并且您不希望将单个作业添加两次。在这种情况下使用:

__cron="1 2 3 4 5 /root/bin/backup.sh"
cat <(crontab -l) |grep -v "${__cron}" <(echo "${__cron}")

这仅在您使用 BASH 时才有效。我不知道正确的 DASH (sh) 语法。

更新:如果用户还没有 crontab,这将不起作用。更可靠的方法是:

(crontab -l ; echo "1 2 3 4 5 /root/bin/backup.sh") | sort - | uniq - | crontab - 

或者,如果您的发行版支持它,您也可以使用单独的文件:

echo "1 2 3 4 5 /root/bin/backup.sh" |sudo tee /etc/crond.d/backup

another SO question 中找到了那些。


也许使用 sh 而不是 bash?
仍在使用 sh 获得 sh: 1: Syntax error: "(" unexpected
这仅在您使用 BASH 时才有效。我不知道正确的 DASH (sh) 语法。也更新了答案
fwiw,如果 <( 之间有空格,我会使用 bash 收到此错误。这意味着 < ( 失败但 <( 有效,除非您的日程安排中有星号...
我相信这是正确的方法:cat <(crontab -l |grep -v "${CRON}") <(echo "${CRON}") | crontab -
B
Bartłomiej Semańczyk

如果在那里找不到所需的字符串,则仅编辑 crontab 的变体:

CMD="/sbin/modprobe fcpci"
JOB="@reboot $CMD"
TMPC="mycron"
grep "$CMD" -q <(crontab -l) || (crontab -l>"$TMPC"; echo "$JOB">>"$TMPC"; crontab "$TMPC")

u
user11547308
echo "0 * * * * docker system prune --force >/dev/null 2>&1" | sudo tee /etc/cron.daily/dockerprune

谢谢!我只想补充一点,一般的 crons 也有 /etc/cron.d。我猜 /etc/cron.daily 仅适用于每日计划。
c
chuck

如果您正在使用 Vixie Cron,例如在大多数 Linux 发行版上,您可以将一个文件放在 /etc/cron.d 中,并带有单独的 cronjob。

这当然只适用于root。如果您的系统支持这一点,您应该会在其中看到几个示例。 (注意该行中包含的用户名,与旧的 /etc/crontab 语法相同)

cron 中的一个可悲的错误功能是作为普通用户无法处理这个问题,而且这么多 cron 实现根本无法处理这个问题。


g
gsus

我对此的首选解决方案是:

(crontab -l | grep . ; echo -e "0 4 * * * myscript\n") | crontab -

这将确保您正确处理底部的空白新行。为避免 crontab 出现问题,您通常应该以空白新行结束 crontab 文件。上面的脚本确保它首先使用“grep”删除任何空白行。部分,然后在脚本末尾添加一个带有“\n”的新空行。如果您现有的 crontab 文件以空行结尾,这也将防止在新命令上方出现空行。


a
akash

用于在没有交互式编辑器的情况下添加 cron 作业的 Bash 脚本。下面的代码有助于使用 linux 文件添加 cronjob。

#!/bin/bash

cron_path=/var/spool/cron/crontabs/root

#cron job to run every 10 min.
echo "*/10 * * * * command to be executed" >> $cron_path

#cron job to run every 1 hour.
echo "0 */1 * * * command to be executed" >> $cron_path

我知道这是一个很长的时间,但这仍然是唯一好的答案,因为所有投票最多的人都删除了旧的 crons 而不是仅仅附加新的。
这个没有安装cron。它只是将其附加到文件中。您将不得不以某种方式通知 cron 进程来安装新条目。
A
Anh Quach

(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 新的 cron 到 cron 文件中

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

#安装新的cron文件

crontab mycron

rm mycron

K
Klas Mellbourn

这是一个 bash 函数,用于向 crontab 添加命令而不重复

function addtocrontab () {
  local frequency=$1
  local command=$2
  local job="$frequency $command"
  cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -
}
addtocrontab "0 0 1 * *" "echo hello"

s
speefak
CRON="1 2 3 4 5 /root/bin/backup.sh" 
cat < (crontab -l) |grep -v "${CRON}" < (echo "${CRON}")

将 -w 参数添加到 grep 精确命令,没有 -w 参数添加 cronjob“testing”会导致删除 cron 作业“testing123”

添加/删除 cronjobs 的脚本函数。没有重复条目:

cronjob_editor () {         
# usage: cronjob_editor '<interval>' '<command>' <add|remove>

if [[ -z "$1" ]] ;then printf " no interval specified\n" ;fi
if [[ -z "$2" ]] ;then printf " no command specified\n" ;fi
if [[ -z "$3" ]] ;then printf " no action specified\n" ;fi

if [[ "$3" == add ]] ;then
    # add cronjob, no duplication:
    ( crontab -l | grep -v -F -w "$2" ; echo "$1 $2" ) | crontab -
elif [[ "$3" == remove ]] ;then
    # remove cronjob:
    ( crontab -l | grep -v -F -w "$2" ) | crontab -
fi 
} 
cronjob_editor "$1" "$2" "$3"

测试:

$ ./cronjob_editor.sh '*/10 * * * *' 'echo "this is a test" > export_file' add
$ crontab  -l
$ */10 * * * * echo "this is a test" > export_file

如果您在 crontab 中有两次相同的命令(在不同时间运行),则删除将删除这两行。
a
andcoz

不,crontab 中没有修改 cron 文件的选项。

您必须:获取当前的 cron 文件(crontab -l > newfile),更改它并将新文件放置到位(crontab newfile)。

如果您熟悉 perl,则可以使用此模块 Config::Crontab

律师事务所,安德里亚


佚名

添加 cronjobs 的脚本函数。检查重复条目,可用表达式 * > "

cronjob_creator () {         
# usage: cronjob_creator '<interval>' '<command>'

  if [[ -z $1 ]] ;then
    printf " no interval specified\n"
elif [[ -z $2 ]] ;then
    printf " no command specified\n"
else
    CRONIN="/tmp/cti_tmp"
    crontab -l | grep -vw "$1 $2" > "$CRONIN"
    echo "$1 $2" >> $CRONIN
    crontab "$CRONIN"
    rm $CRONIN
fi
}

测试:

$ ./cronjob_creator.sh '*/10 * * * *' 'echo "this is a test" > export_file'
$ crontab  -l
$ */10 * * * * echo "this is a test" > export_file

来源:我的大脑;)


J
Juno Sprite

假设您以用户“ubuntu”的身份登录,但您想将作业添加到其他用户的 crontab,例如“john”。您可以执行以下操作:

(sudo crontab -l -u john; echo "* * * * * command") | awk '!x[$0]++' | sudo crontab -u john -

此解决方案的大部分来源:https://www.baeldung.com/linux/create-crontab-script

我在尝试将作业添加到另一个用户的 crontab 时遇到了很多问题。它一直在复制 crontab,或者干脆直接删除它们。不过,经过一些测试,我相信这行代码会以非破坏性的方式将新作业附加到指定用户的 crontab 中,包括不创建已经存在的作业。


F
Ferran Maylinch

我想找到一个这样的例子,所以也许它有帮助:

COMMAND="/var/lib/postgresql/backup.sh"
CRON="0 0 * * *"
USER="postgres"
CRON_FILE="postgres-backup"
# At CRON times, the USER will run the COMMAND
echo "$CRON $USER $COMMAND" | sudo tee /etc/cron.d/$CRON_FILE
echo "Cron job created. Remove /etc/cron.d/$CRON_FILE to stop it."