英文:
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
可以正常运行,日志也可以生成等。
错误分析
- 关于错误位置
我看到日志没有生成,所以我猜想在执行cron中的命令之前或之后,进程可能会中断。
所以问题一定出现在cron中。
肯定不是ansible playbook的问题。
如果我在终端中手动运行
bash /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh
脚本可以正常运行,只有应该由cron触发的自动执行没有启动。
所以我猜想问题出现在cron文件和bash脚本的可访问性之间。
- 关于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"。
- 关于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 >/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-%m).log 2>&1
会导致
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
并且破坏了cron文件。
在上面的第一行中,我在月份变量(%m)的百分号前面添加了一个转义(\)字符,所以现在它是
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
英文:
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 >/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-%m).log 2>&1
would result in
00 07 1 * * myuser /home/myuser/var/myfolder/ansible-am/collect_sale_statistics.sh >/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-
# new line
m).log 2>&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 >/home/myuser/var/log/collect_sale_statistics-$(date +\%Y-\%m).log 2>&1
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论