通常,crontab
脚本未按计划执行或未按预期执行。原因有很多:
- 错误的crontab表示法
- 权限问题
- 环境变量
该社区Wiki旨在汇总crontab
未按预期执行脚本的主要原因。将每个原因写在单独的答案中。
请为每个答案提供一个原因-未执行原因的详细信息-并出于该原因进行修复。
请仅编写特定于cron的问题,例如,命令会在shell中按预期执行,但cron错误地执行。
通常,crontab
脚本未按计划执行或未按预期执行。原因有很多:
该社区Wiki旨在汇总crontab
未按预期执行脚本的主要原因。将每个原因写在单独的答案中。
请为每个答案提供一个原因-未执行原因的详细信息-并出于该原因进行修复。
请仅编写特定于cron的问题,例如,命令会在shell中按预期执行,但cron错误地执行。
Answers:
不同的环境
Cron将最少的环境变量集传递给您的工作。要查看差异,请添加一个虚拟作业,如下所示:
* * * * * env> /tmp/env.output
等待/tmp/env.output
创建,然后再次删除作业。现在,将您的内容/tmp/env.output
与env
常规终端中run 的输出进行比较。
这里常见的“陷阱”是PATH
环境变量不同。也许你的cron脚本使用命令somecommand
中发现/opt/someApp/bin
,你已经加入PATH
的/etc/environment
?cron会PATH
从该文件中忽略,因此somecommand
使用cron运行时从脚本运行将失败,但是在终端中运行时可以运行。值得注意的是,from的变量/etc/environment
将传递给cron作业,而不是cron专门设置的变量,例如PATH
。
为了解决这个问题,只需PATH
在脚本顶部设置您自己的变量。例如
#!/bin/bash
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# rest of script follows
有些人更喜欢只使用绝对路径访问所有命令。我建议反对。考虑如果要在另一个系统上运行脚本,并且在该系统上运行命令,会发生什么情况/opt/someAppv2.2/bin
。您将不得不替换整个脚本/opt/someApp/bin
,/opt/someAppv2.2/bin
而不仅仅是在脚本的第一行进行少量编辑。
您还可以在crontab文件中设置PATH变量,该变量将应用于所有cron作业。例如
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15 1 * * * backupscript --incremental /home /root
env
,我完全忘记了该命令,并认为PATH在起作用。在我看来,这实际上是完全不同的。
我最要注意的是:如果您忘记在crontab
文件末尾添加换行符。换句话说,crontab文件应以空行结尾。
以下是手册页中有关此问题的相关部分(man crontab
然后跳到最后):
Although cron requires that each entry in a crontab end in a newline
character, neither the crontab command nor the cron daemon will detect
this error. Instead, the crontab will appear to load normally. However,
the command will never run. The best choice is to ensure that your
crontab has a blank line at the end.
4th Berkeley Distribution 29 December 1993 CRONTAB(1)
man crontab
在Ubuntu 10.10上,“ cron要求crontab中的每个条目都以换行符结尾。如果crontab中的最后一个条目缺少换行符,则cron会认为crontab(至少部分)已损坏并拒绝安装它。” (最后日期为2010年4月19日。)
crontab -e
,它将在允许保存之前检查文件的语法,包括检查换行符。
-e
选项保存crontab ,并且独立于编辑器。
Cron守护程序未运行。几个月前,我真的搞砸了。
类型:
pgrep cron
如果看不到数字,则说明cron没有运行。sudo /etc/init.d/cron start
可以用来启动cron。
编辑:而不是通过/etc/init.d调用初始化脚本,而是使用服务实用程序,例如
sudo service cron start
编辑:也可以在现代Linux中使用systemctl,例如
sudo systemctl start cron
pidof cron
它将忽略其他也带有单词“ cron”的应用程序的结果,例如crontab。
sudo service cron start
我会得到start: Job is already running: cron
service crond start
如果其centos / RHEL
该脚本档案名称中cron.d/
,cron.daily/
,cron.hourly/
等,不应包含点(.
),否则运行部分将跳过他们。
参见运行部件(8):
If neither the --lsbsysinit option nor the --regex option is given then
the names must consist entirely of upper and lower case letters, dig‐
its, underscores, and hyphens.
If the --lsbsysinit option is given, then the names must not end in
.dpkg-old or .dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong to
one or more of the following namespaces: the LANANA-assigned namespace
(^[a-z0-9]+$); the LSB hierarchical and reserved namespaces
(^_?([a-z0-9_.]+-)+[a-z0-9]+$); and the Debian cron script namespace
(^[a-zA-Z0-9_-]+$).
所以,如果你有一个cron脚本backup.sh
,analyze-logs.pl
在cron.daily/
目录中,你最好删除的扩展名。
run-parts --test
(或像另一个假想的选项--debug
将输出它跳过其中的原因的文件。
在许多环境中,cron使用来执行命令sh
,而许多人则认为它将使用bash
。
建议针对失败的命令进行测试或解决:
尝试在其中运行命令sh
以查看其是否有效:
sh -c "mycommand"
将命令包装在bash子外壳中,以确保它可以在bash中运行:
bash -c "mybashcommand"
通过在crontab顶部设置外壳,告诉cron在bash中运行所有命令:
SHELL=/bin/bash
如果命令是脚本,请确保该脚本包含shebang:
#!/bin/bash
bash
,脚本将手动运行就可以了,但是使用不会cron
。谢谢!
source
以bash而不是sh开头。在cron / sh中,使用句点:. envfile
而不是source envfile
。
sh "mycommand"
告诉我sh
将mycommand作为脚本文件运行。你是说sh -c "mycommand"
吗 无论如何,这个答案似乎与使命令专门在bash中运行有关,那么为什么在这里添加命令sh
呢?
脚本应使用绝对路径:
例如,/bin/grep
应使用代替grep
:
# m h dom mon dow command
0 0 * * * /bin/grep ERROR /home/adam/run.log &> /tmp/errors
代替:
# m h dom mon dow command
0 0 * * * grep ERROR /home/adam/run.log &> /tmp/errors
这特别棘手,因为从shell执行该命令时,该命令将起作用。原因是cron
没有PATH
与用户相同的环境变量。
/usr/bin/whatever
路径
如果您的crontab命令中包含%
符号,则cron尝试对其进行解释。因此,如果您在其中使用任何命令%
(例如date命令的格式说明),则需要对其进行转义。
这和其他好的陷阱在这里:http :
//www.pantz.org/software/cron/croninfo.html
用户的密码也可能已过期。甚至root的密码也可能过期。您可以tail -f /var/log/cron.log
看到cron失败,密码已过期。您可以通过以下操作将密码设置为永不过期:passwd -x -1 <username>
在某些系统(Debian,Ubuntu)中,默认情况下未启用cron日志记录。在/etc/rsyslog.conf或/etc/rsyslog.d/50-default.conf中,该行:
# cron.* /var/log/cron.log
应该在不加sudo nano /etc/rsyslog.conf
注释的情况下进行编辑():
cron.* /var/log/cron.log
之后,您需要通过以下方式重新启动rsyslog
/etc/init.d/rsyslog restart
要么
service rsyslog restart
来源:在Debian Linux中启用crontab日志记录
在某些系统(Ubuntu)中,默认情况下未启用cron的单独日志文件,但是cron相关的日志显示在syslog文件中。一个可以使用
cat /var/log/syslog | grep cron -i
查看与cron相关的消息。
恐怕许可问题很普遍。
请注意,一个常见的解决方法是使用root的crontab执行所有操作,有时这是一个非常糟糕的主意。设置适当的权限肯定是一个很大程度上被忽略的问题。
如果cron表的权限不安全,则拒绝该表
sudo service cron restart
grep -i cron /var/log/syslog|tail -2
2013-02-05T03:47:49.283841+01:00 ubuntu cron[49906]: (user) INSECURE MODE (mode 0600 expected) (crontabs/user)
问题解决了
# correct permission
sudo chmod 600 /var/spool/cron/crontabs/user
# signal crond to reload the file
sudo touch /var/spool/cron/crontabs
脚本对位置敏感。这与在脚本中始终使用绝对路径有关,但并不完全相同。您的cron作业可能需要cd
在运行之前进入特定目录,例如,Rails应用程序上的rake任务可能需要位于应用程序根目录中,以便Rake找到正确的任务,更不用说适当的数据库配置了,等等。
因此,
23 3 * * * /usr/bin/rake db:session_purge RAILS_ENV=production
会更好
23 3 * * * cd / var / www / production / current && / usr / bin / rake db:session_purge RAILS_ENV = production
或者,为了使crontab条目更简单且不那么脆弱:
23 3 * * * /home/<user>/scripts/session-purge.sh
在以下代码中/home/<user>/scripts/session-purge.sh
:
cd / var / www / production / current / usr / bin / rake db:session_purge RAILS_ENV =生产
chdir(dirname(__FILE__));
从过去的 Crontab规范在从一个crontab文件移动到另一个文件时可能会中断。有时原因是您已将规范从系统crontab文件移至用户crontab文件,反之亦然。
用户的crontab文件(/ var / spool / cron /用户名或/ var / spool / cron / crontabs /用户名)与系统crontabs(/etc/crontab
以及中的文件/etc/cron.d
)之间的cron作业规范格式不同。
系统crontab在命令运行之前有一个额外的字段“用户”。
这将导致错误,说明george; command not found
您将命令移出/etc/crontab
或/etc/cron.d
移入用户的crontab文件时的情况。
相反,/usr/bin/restartxyz is not a valid username
当发生相反的情况时,cron将传递类似或类似的错误。
cron脚本正在调用带有--verbose选项的命令
我的cron脚本失败了,因为我在键入脚本时处于自动驾驶仪状态,并且包括--verbose选项:
#!/bin/bash
some commands
tar cvfz /my/archive/file.tar.gz /my/shared/directory
come more commands
从shell执行时,脚本运行良好,但是从crontab运行时,脚本运行失败,因为从shell运行时,详细输出进入stdout,但是从crontab运行时,无处输出。轻松修复以删除“ v”:
#!/bin/bash
some commands
tar cfz /my/archive/file.tar.gz /my/shared/directory
some more commands
我见过cron失败的最常见原因是时间表不正确。指定一个计划在11:15 pm的作业15 23 * * *
来代替 * * 11 15 *
或,这是需要练习的11 15 * * *
。午夜后的工作一周中的一天也迷糊MF是2-6
午夜后,不是1-5
。特定日期通常是个问题,因为我们很少使用* * 3 1 *
3月3日。如果不确定,请访问https://crontab.guru/在线检查您的cron计划。
如果您使用不支持的选项(例如2/3
时间规格)在不同平台上工作也会导致失败。这是一个非常有用的选项,但并非通用。我也遇到过类似清单1-5
或的问题1,3,5
。
使用不合格的路径也会引起问题。默认路径通常是,/bin:/usr/bin
因此将仅运行标准命令。这些目录通常没有所需的命令。这也会影响使用非标准命令的脚本。其他环境变量也可能会丢失。
破坏现有的crontab完全导致了我的问题。我现在从文件副本加载。可以使用现有的crontab crontab -l
对其进行破坏来恢复它。我将crontab的副本保留在〜/ bin中。全文注释,以该行结尾# EOF
。这是每天从crontab条目中重新加载的,例如:
#!/ usr / bin / crontab #重新加载此crontab # 54 12 * * * $ {HOME} / bin / crontab
上面的reload命令依赖于具有运行crontab的爆炸路径的可执行crontab。某些系统需要在命令中运行crontab并指定文件。如果该目录是网络共享的,那么我经常将其crontab.$(hostname)
用作文件名。这最终将纠正在错误的服务器上加载了错误的crontab的情况。
使用该文件可备份crontab的内容,并允许自动撤消临时编辑(我只有一次使用crontab -e
)。有可用的标题,可帮助正确设置调度参数。当没有经验的用户编辑crontab时,我已经添加了它们。
我很少遇到需要用户输入的命令。尽管有些将与输入重定向一起使用,但这些命令在crontab下失败。
30 23 * * *
翻译成晚上11:15吗?
15 23 * * *
。现在已更正。
如果您正在通过SSH密钥访问帐户,则可以登录该帐户,但不会注意到该帐户的密码已锁定(例如,由于过期或无效的密码尝试)
如果系统使用PAM并且帐户已锁定,则可以停止其cronjob运行。(我已经在Solaris上测试过,但是在Ubuntu上没有测试过)
您可以在/ var / adm / messages中找到以下消息:
10月24日07:51:00 mybox cron [29024]:[ID 731128 auth.notice] pam_unix_account:cron尝试从本地主机验证锁定帐户myuser 10月24日07:52:00 mybox cron [29063]:[ID 731128 auth.notice] pam_unix_account:cron尝试从本地主机验证锁定帐户myuser 10月24日07:53:00 mybox cron [29098]:[ID 731128 auth.notice] pam_unix_account:cron尝试从本地主机验证锁定帐户myuser 10月24日07:54:00 mybox cron [29527]:[ID 731128 auth.notice] pam_unix_account:cron尝试从本地主机验证锁定帐户myuser
您所需要做的就是运行:
#passwd -u <用户名>
以root身份解锁帐户,然后crontab应该可以再次使用。
如果您有这样的命令:
* * * * * /path/to/script >> /tmp/output
并且它不起作用,并且您看不到任何输出,这不一定意味着cron不起作用。该脚本可能已损坏,并且输出将传递到stderr,该输出不会传递到/ tmp / output。通过捕获以下输出,检查是否存在这种情况:
* * * * * /path/to/script >> /tmp/output 2>&1
看看这是否可以帮助您解决问题。
=== Docker警报===
如果您使用的是docker,
我认为应该补充一点,我无法使cron在后台运行。
为了在容器中运行cron作业,我使用了supervisor和ran cron -f
以及其他过程。
编辑:另一个问题-使用HOST网络运行容器时,我也无法使其正常工作。也可以在这里查看此问题:https : //github.com/phusion/baseimage-docker/issues/144
我正在编写一个安装Shell脚本,该脚本创建另一个脚本以从数据库中清除旧的事务数据。作为任务的一部分,它必须将日常cron
作业配置为在数据库负载较低时在任意时间运行。
我mycronjob
使用cron计划,用户名和命令创建了一个文件,并将其复制到/etc/cron.d
目录中。我的两个陷阱:
mycronjob
文件必须由root拥有才能运行权限问题将以/var/log/syslog
类似于以下内容的形式出现:
Apr 24 18:30:01 ip-11-22-33-44 cron[40980]: (*system*) INSECURE MODE (group/other writable) (/etc/crontab)
Apr 24 18:30:01 ip-11-22-33-44 cron[40980]: (*system*) INSECURE MODE (group/other writable) (/etc/cron.d/user)
第一行是/etc/crontab
文件,第二行是我放置在的文件/etc/cront.d
。
以crontab无法理解的方式编写的行。需要正确编写。这是CrontabHowTo。
通过“ crontab -e”在一行中使用username参数写入cron。我已经看到了一些用户(或系统管理员)编写其Shell脚本并且不理解为什么他们不自动化的示例。“用户”参数存在于/ etc / crontab中,但不存在用户定义的文件。因此,例如,您的个人文件如下所示:
# m h dom mon dow command
* * */2 * * /some/shell/script
而/ etc / crontab将是:
# m h dom mon dow user command
* * */2 * * jdoe /some/shell/script
那么,为什么要选择后者呢?好吧,这取决于您要如何设置权限,这可能会令人费解。我已经编写了脚本来为不了解复杂性或不想打扰工作的用户自动执行任务。通过将权限设置为--x------
,我可以使脚本可执行,而无需他们能够读取(或不小心更改)脚本。但是,我可能希望从一个文件中与其他几个命令一起运行此命令(从而使维护更容易),但要确保为文件输出分配了正确的所有者。这样做(至少在Ubuntu 10.10中)打破了既无法读取文件又无法执行的问题,还打破了前面提到的在/ etc / crontab中放置句点的问题(有趣的是,遍历时不会引起错误crontab -e
) 。
作为示例,我已经看到了sudo crontab -e
用于以root权限运行脚本的实例,并且chown username file_output
在shell脚本中具有相应的实例。马虎,但它的工作原理。恕我直言,更/etc/crontab
合适的选择是使用声明的用户名和适当的权限将其放入,因此file_output
转到正确的位置和所有者。
基于Aaron Peart所说的详细模式,有时候,如果包含的命令的默认行为是在proc启动后在屏幕上输出一行或更多行,则不是处于详细模式的脚本会初始化但无法完成。例如,我为我们的Intranet编写了一个备份脚本,该脚本使用curl实用程序,该实用程序将文件下载或上传到远程服务器,并且如果您只能通过HTTP访问该远程文件,则非常方便。使用'curl http://something.com/somefile.xls '导致我编写的脚本挂起并从未完成,因为它会吐出换行符和进度行。我必须使用静默标志(-s)来指示它不输出任何信息,并编写自己的代码来处理文件下载失败的情况。
/dev/null
。例如:some-command > /dev/null
这将仅重定向标准输出,而不重定向错误输出(这通常是您想要的,因为您希望被告知错误)。要也重定向错误输出,请使用some-command &> /dev/null
。
尽管您可以在crontable中定义环境变量,但是您不在shell脚本中。因此,类似以下的构造将无法正常工作:
SOME_DIR=/var/log
MY_LOG_FILE=${SOME_LOG}/some_file.log
BIN_DIR=/usr/local/bin
MY_EXE=${BIN_DIR}/some_executable_file
0 10 * * * ${MY_EXE} some_param >> ${MY_LOG_FILE}
这是因为变量未在crontable中解释:所有值都是乱七八糟的。如果省略括号,这是相同的。这样您的命令将不会运行,并且您的日志文件也不会被写入...
相反,您必须直接定义所有环境变量:
SOME_DIR=/var/log
MY_LOG_FILE=/var/log/some_file.log
BIN_DIR=/usr/local/bin
MY_EXE=/usr/local/bin/some_executable_file
0 10 * * * ${MY_EXE} some_param >> ${MY_LOG_FILE}
在cron中运行任务时,stdin将关闭。基于stdin是否可用而行为不同的程序在shell会话和cron中的行为将有所不同。
一个示例是goaccess
用于分析Web服务器日志文件的程序。这在cron中不起作用:
goaccess -a -f /var/log/nginx/access.log > output.html
并goaccess
显示帮助页面,而不是创建报告。在外壳中可以用
goaccess -a -f /var/log/nginx/access.log > output.html < /dev/null
解决的方法goaccess
是使其从stdin中读取日志,而不是从文件中读取日志,因此解决方案是将crontab条目更改为
cat /var/log/nginx/access.log | goaccess -a > output.html
就我而言,cron和crontab具有不同的所有者。
不工作,我有这个:
User@Uva ~ $ ps -ef | grep cron | grep -v grep
User 2940 7284 pty1 19:58:41 /usr/bin/crontab
SYSTEM 11292 636 ? 22:14:15 /usr/sbin/cro
基本上,我必须运行cron-config并正确回答问题。有时需要输入“用户”帐户的Win7用户密码。从我的阅读看来,这似乎是一个潜在的安全问题,但是我是单个家庭网络上的唯一管理员,因此我认为还可以。
这是让我前进的命令序列:
User@Uva ~ $ cron-config
The cron daemon can run as a service or as a job. The latter is not recommended.
Cron is already installed as a service under account LocalSystem.
Do you want to remove or reinstall it? (yes/no) yes
OK. The cron service was removed.
Do you want to install the cron daemon as a service? (yes/no) yes
Enter the value of CYGWIN for the daemon: [ ] ntsec
You must decide under what account the cron daemon will run.
If you are the only user on this machine, the daemon can run as yourself.
This gives access to all network drives but only allows you as user.
To run multiple users, cron must change user context without knowing
the passwords. There are three methods to do that, as explained in
http://cygwin.com/cygwin-ug-net/ntsec.html#ntsec-nopasswd1
If all the cron users have executed "passwd -R" (see man passwd),
which provides access to network drives, or if you are using the
cyglsa package, then cron should run under the local system account.
Otherwise you need to have or to create a privileged account.
This script will help you do so.
Do you want the cron daemon to run as yourself? (yes/no) no
Were the passwords of all cron users saved with "passwd -R", or
are you using the cyglsa package ? (yes/no) no
Finding or creating a privileged user.
The following accounts were found: 'cyg_server' .
This script plans to use account cyg_server.
Do you want to use another privileged account name? (yes/no) yes
Enter the other name: User
Reenter: User
Account User already exists. Checking its privileges.
INFO: User is a valid privileged account.
INFO: The cygwin user name for account User is User.
Please enter the password for user 'User':
Reenter:
Running cron_diagnose ...
... no problem found.
Do you want to start the cron daemon as a service now? (yes/no) yes
OK. The cron daemon is now running.
In case of problem, examine the log file for cron,
/var/log/cron.log, and the Windows event log (using /usr/bin/cronevents)
for information about the problem cron is having.
Examine also any cron.log file in the HOME directory
(or the file specified in MAILTO) and cron related files in /tmp.
If you cannot fix the problem, then report it to cygwin@cygwin.com.
Please run the script /usr/bin/cronbug and ATTACH its output
(the file cronbug.txt) to your e-mail.
WARNING: PATH may be set differently under cron than in interactive shells.
Names such as "find" and "date" may refer to Windows programs.
User@Uva ~ $ ps -ef | grep cron | grep -v grep
User 2944 11780 ? 03:31:10 /usr/sbin/cron
User 2940 7284 pty1 19:58:41 /usr/bin/crontab
User@Uva ~ $
crontab -e
才能使cron生效。例如,使用vim可以编辑文件并用于:w
编写文件,但是直到我也退出后,该作业才会添加到cron中。因此,我也要等到以后才能看到这份工作:q
。