CronJob 没有运行
Posted
技术标签:
【中文标题】CronJob 没有运行【英文标题】:CronJob not running 【发布时间】:2022-01-20 09:11:46 【问题描述】:我已经在 ubuntu 环境中为 root 用户设置了一个 cronjob,如下输入crontab -e
34 11 * * * sh /srv/www/live/CronJobs/daily.sh
0 08 * * 2 sh /srv/www/live/CronJobs/weekly.sh
0 08 1 * * sh /srv/www/live/CronJobs/monthly.sh
但是 cronjob 没有运行。我尝试使用pgrep cron
检查 cronjob 是否正在运行,并且进程 ID 为 3033。shell 脚本调用 python 文件并用于发送电子邮件。运行python文件就可以了。它没有错误,但 cron 没有运行。 daily.sh 文件中包含以下代码。
python /srv/www/live/CronJobs/daily.py
python /srv/www/live/CronJobs/notification_email.py
python /srv/www/live/CronJobs/log_kpi.py
【问题讨论】:
请记住,cron 作业不会在交互式命令的所有环境中运行 - 例如,当您调用“python”时,它会根据环境查找完整的文件路径变量 $PATH。您应该完整指定路径以避免这种依赖关系。 另一类 crontab 问题这里没有涉及到PATH
/environment 相关问题,在Running a bash script from a cronjob fails with “No such file or directory” 中涉及。
【参考方案1】:
WTF?!我的 cronjob 没有运行?!
这是调试未运行 cronjobs 的清单指南:
-
Cron 守护程序是否正在运行?
ps ax | grep cron
并查找 cron。
Debian:service cron start
或 service cron restart
-
cron 工作正常吗?
* * * * * /bin/echo "cron works" >> /tmp/file
语法正确吗?见下文。
您显然需要对要将输出重定向到的文件具有写入权限。 /tmp
中当前不存在的唯一文件名应该始终是可写的。
可能还添加2>&1
以包括标准错误以及标准输出,或者单独将标准错误输出到另一个带有2>>/tmp/errors
的文件
-
该命令是否独立运行?
-
cron 可以运行你的工作吗?
/var/log/cron.log
或/var/log/messages
是否有错误。
Ubuntu:grep CRON /var/log/syslog
红帽:/var/log/cron
-
检查权限
chmod +x /var/www/app/cron/do-stuff.php
如果您将命令的输出重定向到文件,请确认您有权写入该文件/目录
-
检查路径
PATH
这样的环境变量,因为它们在cron 下的值可能与交互式会话下的不同。见How to get CRON to call in the correct PATHs
-
调试时不要抑制输出
30 1 * * * command > /dev/null 2>&1
通过完全删除>/dev/null 2>&1
重新启用标准输出或标准错误消息输出;或者重定向到您具有写入权限的位置的文件:>>cron.out 2>&1
会将标准输出和标准错误附加到调用用户主目录中的cron.out
。
如果您不重定向来自cron
作业的输出,则守护程序将尝试通过电子邮件向您发送任何输出或错误消息。检查您的收件箱(如果您没有邮件客户端,可能只是 more $MAIL
)。如果邮件不可用,可能检查您的主目录中名为dead.letter
的文件,或说明输出已被丢弃的系统日志条目。特别是在后一种情况下,可能会编辑作业以将重定向添加到文件,然后等待作业运行,并检查日志文件以获取错误消息或其他有用的反馈。
如果您试图找出失败的原因,错误消息将在此文件中可见。阅读并理解它。
还是不行?哎呀!
-
提高 cron 调试级别
/etc/default/cron
设置EXTRA_OPTS="-L 2"
service cron restart
tail -f /var/log/syslog
查看执行的脚本
Ubuntu
在/etc/rsyslog.d/50-default.conf
添加或注释掉行cron.* /var/log/cron.log
重新加载记录器sudo /etc/init.d/rsyslog restart
重新运行 cron
打开/var/log/cron.log
并查看详细的错误输出
提醒:调试完成后停用日志级别
-
运行 cron 并再次检查日志文件
Cronjob 语法
# Minute Hour Day of Month Month Day of Week User Command
# (0-59) (0-23) (1-31) (1-12 or Jan-Dec) (0-6 or Sun-Sat)
0 2 * * * root /usr/bin/find
此语法仅对root
用户正确。普通用户 crontab
语法没有 User 字段(普通用户不允许像任何其他用户一样运行代码);
# Minute Hour Day of Month Month Day of Week Command
# (0-59) (0-23) (1-31) (1-12 or Jan-Dec) (0-6 or Sun-Sat)
0 2 * * * /usr/bin/find
Crontab 命令
crontab -l
列出所有用户的 cron 任务。
crontab -e
,对于特定用户:crontab -e -u agentsmith
启动 crontab 文件的编辑会话。
退出编辑器时,会自动安装修改后的 crontab。
crontab -r
从 cron 假脱机程序中删除您的 crontab 条目,而不是从 crontab 文件中。
【讨论】:
这里可能应该包括一些额外的点:1)在测试您的命令时,以您正在编辑的 crontab 的用户身份进行测试,这可能不是您的登录名或 root; 2)正如我上面提到的,最好不要依赖像PATH
这样的环境变量,因为它们在cron下的值可能与交互式会话下的不同。
检查清单的另一件事:确保您尝试执行的任何内容不在加密(主)文件夹中。
Linux 使用扩展的crontab
语法,它支持*/5
或3,11,19
等时间表达式。如果您尝试使用这样的表达式并且您不是在完整的 Linux/Vixie cron
上,请查看本地手册页是否支持这些表达式。
另外,请确保 cron 作业的用户没有过期的密码。
Daaaamn 老兄。这个答案…………!11【参考方案2】:
crontab 失败的另一个原因:%
字符的特殊处理。
来自manual file:
The entire command portion of the line, up to a newline or a
"%" character, will be executed by /bin/sh or by the shell specified
in the SHELL variable of the cronfile. A "%" character in the
command, unless escaped with a backslash (\), will be changed into
newline characters, and all data after the first % will be sent to
the command as standard input.
在我的特殊情况下,我使用 date --date="7 days ago" "+%Y-%m-%d"
为我的脚本生成参数,但它默默地失败了。当我检查syslog
并看到我的命令在%
符号处被截断时,我终于发现了发生了什么。你需要像这样逃避它:
date --date="7 days ago" "+\%Y-\%m-\%d"
更多详情请看这里:
http://www.ducea.com/2008/11/12/using-the-character-in-crontab-entries/
【讨论】:
这正是我遇到的问题:sh /path/script.sh /path/$(date +%Y-%m-%d).txt
必须是:sh /path/script.sh /path/$(date +\%Y-\%m-\%d).txt
谢谢!就是这样。【参考方案3】:
我终于找到了解决方案。以下是解决方案:-
切勿在要通过 crontab 执行的 python 脚本中使用相对路径。 我做了这样的事情:-
import os
import sys
import time, datetime
CLASS_PATH = '/srv/www/live/mainapp/classes'
SETTINGS_PATH = '/srv/www/live/foodtrade'
sys.path.insert(0, CLASS_PATH)
sys.path.insert(1,SETTINGS_PATH)
import other_py_files
永远不要抑制 crontab 代码,而是使用 mailserver 并检查用户的邮件。这样可以更清楚地了解正在发生的事情。
【讨论】:
也永远不要忘记顶部的 hashbangs #!/usr/bin/env python :-) 如果您知道自己在做什么,相对路径就可以了。cron
作业将在其作业正在执行的用户的主目录中启动。
如果您的系统未配置为发送电子邮件,任何cron
输出都将丢失。如果您不能 - 或不想 - 在盒子上配置邮件只是为了进行故障排除,可能请确保将 everything 写入日志文件(即* * * * * whatever >>filename 2>&1
您有权写入的位置filename
并了解您可能希望指定应写入文件的目录的完整路径,但如果您不这样做,您指的是您的主目录。【参考方案4】:
我想补充我学到的2点:
-
/etc/cron.d/ 中的 Cron 配置文件不应包含点 (.)。否则,cron 不会读取它。
如果运行您的命令的用户不在 /etc/shadow.不允许安排 cron。
参考:
-
http://manpages.ubuntu.com/manpages/xenial/en/man8/cron.8.html
https://help.ubuntu.com/community/CronHowto
【讨论】:
跳过名称中带有点的文件的约定扩展到任何.d
并且是一个实现细节,我想到了 Debian run-parts
脚本;所以这个建议可能特定于基于 Debian 的架构。【参考方案5】:
要添加另一个点,/etc/cron.d 中的文件必须在末尾包含一个空的新行。这可能与 Luciano 的回应有关,其中指出:
The entire command portion of the line, up to a newline or a "%"
character, will be executed
【讨论】:
当您遇到“一些”您的 crons 正在运行但“不是全部”时,尤其是 cron 选项卡中的最后一个,这可能是原因。 一般来说,所有文本文件在类 Unix 平台上都应该有一个最后的换行符。根据 POSIX,如果没有,它们不是有效的文本文件。【参考方案6】:我发现用户的 crontab 未运行的另一个原因:主机文件中不存在主机名:
user@ubuntu:~$ cat /etc/hostname
ubuntu
现在是主机文件:
user@ubuntu:~$ cat /etc/hosts
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
这是在 Ubuntu 14.04.3 LTS 上,修复它的方法是将主机名添加到主机文件,所以它类似于这样:
user@ubuntu:~$ cat /etc/hosts
127.0.0.1 ubuntu localhost
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
【讨论】:
【参考方案7】:对我来说,解决方案是 cron 试图运行的文件位于加密目录中,更具体地说是 /home/ 上的用户目录。尽管 crontab 被配置为 root,因为正在运行的脚本存在于 /home/ 中的加密用户目录中,所以只有在用户实际登录时,cron 才能读取该目录。要查看该目录是否已加密,请检查该目录是否存在:
/home/.ecryptfs/<yourusername>
如果是这样,那么您就有了一个加密的主目录。
对我来说,解决方法是将脚本移动到非加密目录中,一切正常。
【讨论】:
【参考方案8】:我通过运行在 Ubuntu 16.04 服务器上找到了有用的调试信息:
systemctl status cron.service
在我的情况下,我被告知我在备注行中留下了评论“#”:
Aug 18 19:12:01 is-feb19 cron[14307]: Error: bad minute; while reading /etc/crontab
Aug 18 19:12:01 is-feb19 cron[14307]: (*system*) ERROR (Syntax error, this crontab file will be ignored)
【讨论】:
【参考方案9】:也可能是时区问题。
Cron 使用本地时间。
运行命令timedatectl
查看机器时间并确保您的 crontab 处于同一时区。
【讨论】:
【参考方案10】:我遇到了与以下链接类似的问题。
similar to my problemmy original post
我的问题
我的问题是 cron / crontab 不会执行我的 bash 脚本。该 bash 脚本执行了一个 python 脚本。
原始 bash 文件
#!/bin/bash
python /home/frosty/code/test_scripts/test.py
python 文件 (test.py)
from datetime import datetime
def main():
dt_now = datetime.now()
string_now = dt_now.strftime('%Y-%m-%d %H:%M:%S.%f')
with open('./text_file.txt', 'a') as f:
f.write(f'wrote at string_now\n')
return None
if __name__ == '__main__':
main()
我遇到的错误
File "/home/frosty/code/test_scripts/test.py", line 7
string_to_write = f'wrote at string_now\n'
^
SyntaxError: invalid syntax
这个错误没有意义,因为从 bash 文件和 python 文件中执行的代码没有错误。
** 注意 -> 确保在 crontab -e
文件中不要抑制输出。我通过在命令后添加>>/path/to/cron/output/file.log 2>&1
将输出发送到文件。下面是我的 crontab -e 条目
*/5 * * * * /home/frosty/code/test_scripts/echo_message_sh >>/home/frosty/code/test_scripts/cron_out.log 2>&1
问题
cron 使用了错误的 python 解释器,可能是语法错误导致的 python 2。
我是如何解决这个问题的
我将我的 bash 文件更改为以下内容
#!/bin/bash
conda_shell=/home/frosty/anaconda3/etc/profile.d/conda.sh
conda_env=base
source $conda_shell
conda activate $conda_env
python /home/frosty/code/test_scripts/test.py
我将我的 python 文件更改为以下内容
from datetime import datetime
def main():
dt_now = datetime.now()
string_now = dt_now.strftime('%Y-%m-%d %H:%M:%S.%f')
string_file = '/home/frosty/code/test_scripts/text_file.txt'
string_to_write = 'wrote at \n'.format(string_now)
with open(string_file, 'a') as f:
f.write(string_to_write)
return None
if __name__ == '__main__':
main()
【讨论】:
这里有两个不同的问题。如果只是python
运行了错误的 Python 版本,简单的解决方法是指定要运行的版本的路径,比如可能是 /opt/local/python3.10/bin/python
而不仅仅是 python
。虚拟环境具有额外的好处,您可以安装特定于该环境的库;对此的标准解决方案是 Python 3 标准库中的 venv
模块,尽管 Conda 是一种流行的第三方替代方案,具有一些独特的功能。
如果你在$HOME/myprovect/venv
中有一个标准的venv
环境,你想在其中运行$HOME/myproject/script.py
,你不需要单独activate
它;您可以简单地使用$HOME/myproject/venv/bin/python $HOME/myproject/script.py
运行它【参考方案11】:
我遇到了同样的问题,crons 没有运行。 我们通过更改权限和所有者来修复 正如我们在 crontab 和 已授予 Cronjobs 644 权限
【讨论】:
644 对于您想要执行的任何内容都是错误的。一个脚本文件通常应该有 755(或者如果你在一个组总是唯一的体系结构上可能是 775;尽管即使这样 755 也应该工作)。最终,您需要真正了解这些权限的含义。【参考方案12】:已经有很多答案了,但没有一个对我有帮助,所以我会在这里添加我的答案,以防对其他人有用。
在我的情况下,我的 cronjobs 一直在工作,直到出现电力短缺,导致我的 Raspberry Pi 断电。 Cron 损坏了。我认为恰好在短缺发生时它正在运行一个很长的 python 脚本。上面的主要答案中没有任何内容对我有用。然而,解决方案非常简单。我只需要强制重新安装 cron:
sudo apt-get --reinstall install cron
它在此之后立即工作。
【讨论】:
【参考方案13】:在此处复制我对a duplicated question 的回答。
cron 可能不知道在哪里可以找到 Python 解释器,因为它不共享您的用户帐户的环境变量。
有3个解决方案:
如果 Python 位于 /usr/bin/python
,您可以将 cron 作业更改为使用绝对路径:/usr/bin/python /srv/www/live/CronJobs/daily.py
或者,您也可以使用 PATH=/usr/bin
将 PATH 值添加到 crontab。
另一种解决方案是在脚本文件中指定解释器,使其可执行,然后在您的 crontab 中调用脚本本身:
一个。将 shebang 放在 python 文件的顶部:#!/usr/bin/python
。
b.将其设置为可执行:$ chmod +x /srv/www/live/CronJobs/daily.py
c。放入crontab:/srv/www/live/CronJobs/daily.py
如果系统上的 Python 解释器路径不同,请调整它。
Reference
【讨论】:
【参考方案14】:由于这已成为解决 cron
问题的规范,请允许我添加一个具体但相当复杂的问题:如果您尝试从 cron
运行 GUI 程序,您可能 做错了.
常见的症状是收到有关 DISPLAY
未设置或 cron
作业的进程无法访问显示的错误消息。
简而言之,这意味着您尝试运行的程序正在尝试在 X11(或 Wayland 等)显示器上呈现某些内容,但失败了,因为 cron
未附加到图形环境,或者实际上任何一种输入/输出工具,除了能够读写文件,如果系统配置允许,还可以发送电子邮件。
出于“我无法运行我的图形cron
作业”的目的,让我们大致指出此问题的三种常见情况。
可能确定您尝试实施的案例,并搜索有关该特定场景的相关问题以了解更多信息,并使用实际代码找到实际解决方案。
如果您正在尝试开发与用户交流的交互式程序,您需要重新考虑您的方法。一个常见但重要的安排是将程序分成两部分:一个可以从cron
运行的后端服务,但它没有任何用户可见的交互设施,以及一个用户运行的前端客户端当他们想要与后端服务通信时,从他们的 GUI 中获取。
如果需要,或者他们希望在用户登录时自动运行,您的用户客户端可能应该简单地添加到用户的 GUI 启动脚本中。
我想后端服务可以从cron
启动,但是如果它需要一个GUI才能使用,也许可以从X11服务器的启动脚本启动它;如果没有,可能从常规启动脚本运行它(systemd
这些天,或者/etc/rc.local
或更传统的类似系统启动目录)。1
如果您尝试在不与真实用户交互的情况下运行 GUI 程序 2,您可以设置“无头”X11 服务器 3 并运行cron
作业,它启动该服务器,运行您的作业,然后退出。
您的工作可能应该简单地从cron
运行合适的 X11 服务器(与管理系统可用的实际物理显示器和连接的显卡和键盘的任何交互式 X11 服务器分开) ,并传递给它一个配置,该配置运行您想要运行的客户端,一旦它启动并运行。 (有关一些实际考虑,另请参阅下一点。)
您运行计算机的唯一目的是在 GUI 中显示特定应用程序,并且您希望在计算机启动时启动该应用程序。
您的启动脚本可能应该简单地运行 GUI(X11 或其他)并挂钩到其启动脚本,以便在 GUI 启动并运行后也运行客户端程序。换句话说,这里不需要cron
;只需配置启动脚本以运行桌面 GUI,并将桌面 GUI 配置为作为(可能是自动的,访客?)登录序列的一部分运行您的应用程序。4
有种方法可以在系统的主显示器 (DISPLAY=:0.0
) 上运行 X11 程序,但从 cron
作业执行此操作通常会出现问题,因为该显示器通常保留用于实际交互使用由第一个登录并启动图形桌面的用户。在单用户系统上,如果该用户也是您,您可能能够忍受副作用,但这往往会带来不便的后果并且扩展性非常差。
另一个复杂的问题是决定以哪个用户身份运行cron
作业。像后端服务这样的共享系统资源可以并且可能应该由root
运行(尽管理想情况下有一个专用的系统帐户,一旦它获得了对其所需的任何特权资源的访问权,它就会切换到该帐户),但是任何涉及 GUI 的东西都应该绝对不能在任何时候以root
运行。
一个相关但不同的问题是以任何有意义的方式与用户交互。如果您可以识别用户的活动会话(在某种程度上,这甚至是一开始就明确定义的),那么您如何在不干扰他们中间的任何其他内容的情况下吸引他们的注意力?但更根本的是,你如何找到它们?如果他们根本没有登录,那你会怎么做?如果是,您如何确定它们是活跃的和可用的?如果他们多次登录,他们使用的是哪个终端,中断该会话是否安全?同样,如果他们登录到 GUI,如果他们实际上是通过 VNC 或远程 X11 服务器远程登录,他们可能会错过您在本地控制台上弹出的窗口。
另外:在专用服务器(网络托管服务、超级计算集群等)上,如果您安装可以从外部连接的交互式图形桌面,您甚至可能违反托管公司或机构的服务条款世界,甚至根本没有。
1cron
中的 @reboot
钩子对于在系统启动时没有任何其他工具来运行某些东西的普通用户来说是一种便利,但是如果你是 root
无论如何,在其中隐藏一些东西只是不方便和晦涩的,并且完全控制系统。使用系统工具启动系统服务。
2 一个常见的用例是运行一个 Web 浏览器,它需要运行一个完整的 GUI 客户端,但它是通过编程方式控制的,实际上不需要在任何地方显示任何东西,例如抓取使用 javascript 的网站,因此需要一个完整的图形浏览器来呈现您要提取的信息。
另一个是设计不佳的科学或办公软件,它不是为批处理使用而编写的,因此即使您只想运行批处理作业然后立即退出而无需在任何地方显示任何内容,也需要 GUI。
(在后一种情况下,可能查看文档以检查是否没有 --batch
或 --noninteractive
或 --headless
或 --script
或 --eval
选项或类似选项以在没有 GUI 的情况下运行该工具,或者可能是用于非交互式使用的单独实用程序。)
3Xvfb
是事实上的标准解决方案;它运行一个“虚拟帧缓冲区”,计算机可以在其中像向显示器一样输出像素,但实际上并未连接到任何显示硬件。
4 这里有几个选项。 最简单的方法是将系统设置为在启动时自动登录特定用户而无需密码提示,并配置该用户的桌面环境(Gnome 或 KDE 或 XFCE 或其他)以从其“启动项”运行脚本或“登录操作”或“自动启动”或任何可能调用的工具。如果您需要对环境进行更多控制,可以在没有桌面环境或窗口管理器的情况下运行裸 X11,而只需运行您的脚本。或者在某些情况下,可以将 X11 登录管理器(“greeter”)替换为自定义构建的东西。
X11 堆栈非常模块化,并且在各个层中有几个挂钩,您可以在其中运行脚本作为标准启动过程的一部分,或者完全替代标准层。这些事情在发行版和实现之间往往会有所不同,并且随着时间的推移,所以这个答案在这些问题上必然是模糊和不完整的。同样,可能会尝试找到有关如何为您的特定平台(Ubuntu、Raspbian、Gnome、KDE 等)和场景做事的现有问题。
【讨论】:
或许也可以看看askubuntu.com/questions/432255/… 关于自动启动 GUI 的东西,另见unix.stackexchange.com/questions/44288/…【参考方案15】:有时 cron 需要运行的命令位于 cron 无权访问的目录中,通常在用户主目录权限为 700 且命令位于该目录中的系统上。
【讨论】:
用户自己可以访问该目录就好了;为什么另一个用户或系统用户想要从cron
或其他地方运行他们的脚本?系统脚本应该归系统所有(当然,如果他们是目标受众,所有用户都可以访问)。以上是关于CronJob 没有运行的主要内容,如果未能解决你的问题,请参考以下文章