为什么我的cron文件中的月度命令不起作用,而每日命令却起作用?

huangapple go评论94阅读模式
英文:

Why does my monthly command in my cron file does not work while daily commands do work?

问题

我正在管理一个在Ubuntu操作系统上由第三方构建的系统。

在一个cron文件中有一行,每个月的第一天的07:00时,应该触发一个调用ansible playbook的bash脚本,并生成一个记录有执行信息的日志。

调用链:

cron文件 -> bash脚本 -> ansible playbook

然而,这并没有起作用:脚本没有运行,日志也没有生成。

问题是什么?

上下文

cron文件位于/etc/cron.d/ansible-cron,其中的关键行是

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh >/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-%m).log 2>&1

bash脚本的权限是

-rwxr-xr-x 1 myuser myuser 493 Mar 23 17:42 collect_sale_statistics.sh*

其内容是

#!/bin/bash

cd /home/myuser/var/myfolder/ansible-am
/home/myuser/var/myfolder/ansible-venv/bin/ansible-playbook playbooks/collect_sale_statistics/main.yml

在我的机器上,相同的例程也用于一些每日和每周的playbook,它们都可以成功运行。

例如,

/etc/cron.d/ansible-cron也包含以下内容:

# 每周一收集上周的重启次数
00 07 * * 1 myuser /home/myuser/var/myfolder/ansible-am/count_reboots.sh >/home/myuser/var/log/count_reboots-$(date +\%w).log 2>&1

bash脚本的权限是

-rwxr-xr-x 1 myuser myuser 771 Feb  8  2023 /home/myuser/var/myfolder/ansible-am/count_reboots.sh*

其内容是

#!/bin/bash

cd /home/myuser/var/myfolder/ansible-am
/home/myuser/var/myfolder/ansible-venv/bin/ansible-playbook playbooks/count_reboots.yml

脚本count_reboots.sh可以正常运行,日志也可以生成等。

错误分析

  1. 关于错误位置

我看到日志没有生成,所以我猜想在执行cron中的命令之前或之后,进程可能会中断。
所以问题一定出现在cron中。
肯定不是ansible playbook的问题。

如果我在终端中手动运行

bash /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh

脚本可以正常运行,只有应该由cron触发的自动执行没有启动。

所以我猜想问题出现在cron文件和bash脚本的可访问性之间。

  1. 关于cron语法

我已经验证了在crontab.guru上设置的00 07 1 * *(用于collect_sale_statistics.sh的cron时间)正确表示"在每个月的1号的07:00"。
这个消息稍微不太清晰,因为"每个月的1号"可以被解释为"每个月的第一个日子",也就是一月份,所以是"每天都在一月份"。
然而,这并不是真的,因为我还在crontab.guru上验证了"每天都在一月份"被cron转码为00 07 * 1 *,crontab.guru表示"在一月份的07:00"。

  1. 关于cron文件夹

我怀疑问题可能出现在我将一个被认为每月运行的命令放在了一个应该包含每天运行命令的/etc/cron.d/文件夹中。

然而,同一个cron文件包含一个每周运行的命令,它运行正常。

英文:

I am managing a system built by third parts on a Ubuntu OS.

There is a line in a cron file which - every first day of the month at hour 07:00 - should trigger a bash script which calls an ansible playbook, and produce a log with the information about the execution.

chain of calls:

cron file -> bash script -> ansible playbook

However this does not work: the script does not run, the log does not get generated.

What is the problem ?

Context

The cron file is /etc/cron.d/ansible-cron, and the line of the case is

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh >/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-%m).log 2>&1

the bash script permissions are

-rwxr-xr-x 1 myuser myuser 493 Mar 23 17:42 collect_sale_statistics.sh*

and its content is

#!/bin/bash

cd /home/myuser/var/myfolder/ansible-am
/home/myuser/var/myfolder/ansible-venv/bin/ansible-playbook playbooks/collect_sale_statistics/main.yml

In my machine, the same routine is implemented for some daily and weekly playbooks which successfully work.

e.g.

The cron /etc/cron.d/ansible-cron also contains:

# collect number of reboot in the last week every monday
00 07 * * 1 myuser /home/myuser/var/myfolder/ansible-am/count_reboots.sh >/home/myuser/var/log/count_reboots-$(date +\%w).log 2>&1

the bash script permissions are

-rwxr-xr-x 1 myuser myuser 771 Feb  8  2023 /home/myuser/var/myfolder/ansible-am/count_reboots.sh*

and its content is

#!/bin/bash

cd /home/myuser/var/myfolder/ansible-am
/home/myuser/var/myfolder/ansible-venv/bin/ansible-playbook playbooks/count_reboots.yml

The script count_reboots.sh runs fine, the log is generated, etc.

error analysis

1. About the error location

What I see is that the log was not generated, so I guess that the process breaks before when or before the command in the cron is executed. <br>
So the problem must be in the cron. <br>
For sure it is not in the ansible playbook. <br>

If I manually run in the terminal

bash /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh

the script runs fine, just the automatic execution which should be triggered by the cron does not start.

So I guess the problem lies somewhere between the cron file and the accessibility to the bash script.

2. About the cron syntax

I have verified on crontab.guru that 00 07 1 * * ( the cron time set for collect_sale_statistics.sh ) correctly means "At 07:00 on day-of-month 1."<br>
This message is slightly unclear, as "day-of-month 1" could be interpreted as "day-of month1", which is January, so "every day in January".<br>
However, this is not the case, as I have also verified on crontab.guru that "every day in January" is cron-transcoded as 00 07 * 1 * , for which crontab.guru indicates "At 07:00 in January.".

3. About the cron folder

I suspect the problem might be in the fact that I am placing a command which is supposed to run monthly in a folder /etc/cron.d/ which should be dedicated to cron files which should contain comands to be run daily.

However, the same cron file contains a command which is run weekly, and it runs fine.

答案1

得分: 0

根据@GordonDavisson和另一个SO线程的引用,cron的手册文档中写道:

...
命令中的百分号(%),除非用反斜杠(\)转义,否则将被更改为换行字符,并且第一个百分号之后的所有数据将被发送到命令作为标准输入。
...

所以我的这一行:

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh &gt;/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-%m).log 2&gt;&amp;1

会导致

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh &gt;/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-
# 新的一行
m).log 2&gt;&amp;1

并且破坏了cron文件。

在上面的第一行中,我在月份变量(%m)的百分号前面添加了一个转义(\)字符,所以现在它是

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh &gt;/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-\%m).log 2&gt;&amp;1
英文:

As quoted by @GordonDavisson and by another SO thread, the manpage documentation for cron says:

...
Percent-signs (%) in the command, unless escaped with backslash (\), 
will be changed into newline characters, and all data after the 
first % will be sent to the command  as standard input.
...

so my line

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh &gt;/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-%m).log 2&gt;&amp;1

would result in

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh &gt;/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-
# new line
m).log 2&gt;&amp;1

and break the cron file.

In the first line above, I have added an escape (\) character before the percent sign of the month variable (%m), so now it is

00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh &gt;/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-\%m).log 2&gt;&amp;1

huangapple
  • 本文由 发表于 2023年8月10日 17:25:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76874367.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定