这是一个典型问题关于使用 cron 和 crontab。
您被引导到这里是因为社区确信您的问题的答案可以在下面找到。如果您的问题没有在下面找到答案,那么答案将帮助您收集信息,从而帮助社区帮助您。这些信息应该被编辑到您的原始问题中。
答案是为什么我的 crontab 不工作?我该如何排除故障?' 如下所示。这将使cron
系统以 crontab 突出显示。
答案1
如何修复所有与 crontab 相关的麻烦/问题(Linux)
这是一个社区维基,如果您发现此答案有任何错误或有其他信息,请编辑它。
一、基本术语:
- cron(8)是执行计划命令的守护进程。
- crontab(1)是用于修改用户 crontab(5) 文件的程序。
- crontab(5)是每个用户都包含 cron(8) 指令的文件。
接下来,关于 cron 的教育:
系统上的每个用户可能都有自己的 crontab 文件。根和用户 crontab 文件的位置取决于系统,但通常位于 下方/var/spool/cron
。
有一个系统范围的/etc/crontab
文件,该/etc/cron.d
目录可能包含 crontab 片段,这些片段也由 cron 读取和执行。一些 Linux 发行版(例如 Red Hat)还具有/etc/cron.{hourly,daily,weekly,monthly}
目录,其中的脚本将以 root 权限每小时/每天/每周/每月执行一次。
root 始终可以使用 crontab 命令;普通用户可能会或可能不会被授予访问权限。当您使用该命令编辑 crontab 文件crontab -e
并保存时,crond 会检查其基本有效性,但不能保证您的 crontab 文件格式正确。有一个名为的文件cron.deny
将指定哪些用户不能使用 cron。该cron.deny
文件的位置取决于系统,可以删除它,这将允许所有用户使用 cron。
如果计算机未启动或 crond 守护程序未运行,并且运行命令的日期/时间已过,则 crond 将不会赶上并运行过去的查询。
crontab 详情,如何制定命令:
crontab 命令由一行表示。您不能使用\
将命令扩展到多行。井号 ( #
) 表示注释,这意味着 cron 会忽略该行上的任何内容。前导空格和空行将被忽略。
%
在命令中使用百分号 ( ) 时要非常小心。除非对它们进行转义,否则\%
它们将转换为换行符,并且第一个非转义字符之后的所有内容都%
将通过 stdin 传递给您的命令。
crontab 文件有两种格式:
用户 crontabs
# Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) # | | | | | # * * * * * command to be executed
系统范围
/etc/crontab
和/etc/cron.d
碎片# Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) # | | | | | # * * * * * user-name command to be executed
注意后者需要用户名。该命令将以指定用户的身份运行。
该行的前 5 个字段表示应运行命令的时间。时间规范中可以使用数字或适当的日期/月份名称。
- 字段之间以空格或制表符分隔。
- 逗号 (
,
) 用于指定列表,例如 1,4,6,8,表示在 1,4,6,8 运行。 - 范围用破折号 (
-
) 指定,并且可以与列表组合,例如 1-3,9-12,表示在 1 到 3 之间,然后在 9 到 12 之间。 - 该
/
字符可用于引入步骤,例如 2/5,这意味着从 2 开始,然后每 5 次(2、7、12、17、22……)。它们不会超出末尾。 *
字段中的星号 ( ) 表示该字段的整个范围(例如0-59
分钟字段)。- 范围和步骤可以组合起来,例如
*/2
表示从相关字段的最小值开始,然后每 2 个,例如 0 表示分钟(0,2 ... 58),1 表示月份(1,3 ... 11)等。
调试 cron 命令
查看邮件!
默认情况下,cron 会将命令的任何输出通过邮件发送给运行该命令的用户。如果没有输出,则不会发送邮件。如果您希望 cron 将邮件发送到其他帐户,则可以在 crontab 文件中设置 MAILTO 环境变量,例如
[email protected]
1 2 * * * /path/to/your/command
自己捕获输出
您可以将 stdout 和 stderr 重定向到文件。捕获输出的确切语法可能因 cron 使用的 shell 而异。以下是将所有输出保存到文件的两个示例/tmp/mycommand.log
:
1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1
查看日志
Cron 通过 syslog 记录其操作,该系统日志(取决于您的设置)通常会转到/var/log/cron
或/var/log/syslog
。
如果需要,你可以使用以下方法过滤 cron 语句:
grep CRON /var/log/syslog
现在我们已经了解了 cron 的基础知识、文件在哪里以及如何使用它们,让我们来看看一些常见的问题。
检查 cron 是否正在运行
如果 cron 没有运行那么您的命令将不会被安排...
ps -ef | grep cron | grep -v grep
应该给你类似的东西
root 1224 1 0 Nov16 ? 00:00:03 cron
或者
root 2018 1 0 Nov14 ? 00:00:06 crond
如果没有,请重新启动
/sbin/service cron start
或者
/sbin/service crond start
可能还有其他方法;请使用您的发行版提供的方法。
cron 在受限环境中运行您的命令。
可用的环境变量可能非常有限。通常,您只会定义几个变量,例如$LOGNAME
、$HOME
和$PATH
。
特别值得注意的是PATH
仅限于/bin:/usr/bin
。绝大多数“我的 cron 脚本不起作用”问题都是由这个限制路径引起的。如果您的命令位于不同的位置,您可以通过以下几种方式解决此问题:
提供命令的完整路径。
1 2 * * * /path/to/your/command
在 crontab 文件中提供合适的 PATH
PATH=/bin:/usr/bin:/path/to/something/else 1 2 * * * command
如果您的命令需要其他环境变量,您也可以在 crontab 文件中定义它们。
cron 使用 cwd == $HOME 运行您的命令
无论你执行的程序位于文件系统的什么位置,cron 运行时程序的当前工作目录将是用户的主目录。如果您在程序中访问文件,则需要考虑到使用相对路径的情况,或者(最好)在任何地方都使用完全限定路径,这样可以避免大家产生很多困惑。
我的 crontab 中的最后一条命令没有运行
Cron 通常要求命令以新行结尾。编辑您的 crontab;转到包含最后一条命令的行尾并插入新行(按 Enter)。
检查 crontab 格式
您不能将用户 crontab 格式的 crontab 用于 /etc/crontab 或 /etc/cron.d 中的片段,反之亦然。用户格式的 crontab 不包含行第 6 个位置的用户名,而系统格式的 crontab 包含用户名并以该用户身份运行命令。
我将文件放入 /etc/cron.{hourly,daily,weekly,monthly} 但它没有运行
- 检查文件名是否没有扩展名,请参见运行部件
- 确保该文件具有执行权限。
- 告诉系统执行脚本时使用什么(例如放在
#!/bin/sh
顶部)
Cron 日期相关错误
如果您的日期最近被用户或系统更新、时区或其他因素更改,那么 crontab 将开始行为异常并出现奇怪的错误,有时工作正常,有时不工作。这是 crontab 试图在时间发生变化时“做您想做的事情”。小时更改后,“分钟”字段将失效。在这种情况下,只接受星号。重新启动 cron 并在不连接互联网的情况下重试(这样日期就没有机会重置为其中一个时间服务器)。
再次使用百分号
为了强调有关百分号的建议,下面是 cron 对它们进行操作的一个例子:
# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz
将创建包含以下 3 行内容的 ~/cron.out 文件
foo
bar
baz
这在使用date
命令时尤其具有干扰性。请务必避开百分号
* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"
如何sudo
在 cron 任务中使用
以非 root 用户身份运行时,
crontab -e
将打开用户的 crontab,同时
sudo crontab -e
将打开 root 用户的crontab
。不建议sudo
在用户cron 任务,因此如果你的 cron 任务需要 root 权限,那么你应该以 root 权限运行该任务crontab
,从命令中删除 sudo。
答案2
Debian Linux 及其衍生产品(Ubuntu、Mint 等)有一些特性,可能会阻止您的 cron 作业执行;特别是中的文件/etc/cron.d
必须/etc/cron.{hourly,daily,weekly,monthly}
:
- 由 root 拥有
- 仅可由 root 写入
- 不可由组或其他用户写入
- 有名字没有任何点 '.'或除 '-' 和 '_' 之外的任何其他特殊字符。
最后一个漏洞会经常伤害毫无戒心的用户;特别是位于以下文件夹中名为whatever.sh
、mycron.py
、testfile.pl
等文件夹中的任何脚本都会不是永远被处决。
根据我的经验,这个特定点是 Debian 和衍生版本中 cronjob 无法执行的最常见原因。
如果有必要的话,请参阅man cron
更多详细信息。
答案3
如果您的 cronjobs 停止工作,请检查您的密码是否过期。因为一旦密码过期,所有 cron 作业都会停止。
将出现/var/log/messages
类似于下面的消息,显示用户身份验证问题:
(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)
答案4
PHP 专用
如果你有如下 cron 任务:
php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log
如果出现错误,系统会将其发送给您,但是却没有——请检查一下。
PHP 默认不发送错误到 STDOUT。@seehttps://bugs.php.net/bug.php?id=22839
为了修复这个问题,在 cli 的 php.ini 或你的行中(或者在你的 PHP 的 bash 包装器中)添加这些:
- --定义 display_startup_errors = 1
- --define display_errors='stderr'
第一种设置将允许您遇到“内存错误”等致命错误,第二种设置 — 将它们全部重定向到 STDERR。只有这样您才能高枕无忧,因为所有错误都将发送到您的根邮件,而不仅仅是记录下来。