为什么我的 crontab 脚本不运行?

为什么我的 crontab 脚本不运行?

我尝试通过 crontab 运行存储在我的主目录中的脚本,但它不起作用。每次运行时,CRON 日志只会显示以下内容:

Sep  3 18:30:01 backup CRON[6778]: (root) CMD (/home/hannes/script > /tmp/yc.log)
Sep  3 18:30:01 backup CRON[6777]: (CRON) info (No MTA installed, discarding output)

计划任务:

*/1 * * * * /home/hannes/script > /tmp/yc.log

如果我尝试添加 .sh 文件扩展名,它不会改变任何内容。yc.log 文件保持为空。

这是我正在尝试执行的脚本(如果我手动运行它,效果会很好):

#!/bin/sh
cp -r -p mnt/main-nas/PATH-TO-FILE mnt/backup-nas/01/temp/server
zip -r mnt/backup-nas/01/1.19_Test.`date +%d.%m.%Y_%H.%M.%S`.zip mnt/backup-nas/01/temp/server
rm -r mnt/backup-nas/01/temp/server

任何帮助都将不胜感激!:)

答案1

你的脚本实际正在运行……但某处出错了。由于您没有捕获stderr输出,因此 stderr 会发送cron给在本地运行脚本的用户。(并且也会失败)

根本原因是:您的脚本仅重定向stdout到文件。然而,许多失败的脚本和程序都习惯于stderr输出其错误消息。您需要通过在执行的2>&1命令行末尾添加来捕获该消息cron,这也会捕获stderr错误并将其记录到您的文件中。

由于您之前没有捕获到它,stderr 是通过邮件传递的root- 但因为您没有本地 MTA(邮件传输代理,又称本地邮件传输协议 (LMTP) 服务器)来进行本地传递,所以您遇到了这些 cron 错误。通过捕获,stderr您现在将看到错误以及您的脚本无法正常运行的原因。

一旦日志中出现错误输出,您就可以进一步调试脚本以确定需要做什么来“修复”问题。

答案2

所以有几个问题。首先,我忘记添加2>&1结尾/home/hannes/script > /tmp/yc.log,以便日志能够真正保存。其次,我的脚本中有一个拼写错误,我忘记了所有路径中的第一个斜杠。它从这个变成了home/hannes/...这个/home/hannes/...。我希望这可以帮助其他遇到类似问题的人,并感谢所有回复的人 :)

答案3

接受的答案是正确的,涵盖了所述问题。但是,问题中提供的信息表明此脚本存在一个不相关的潜在问题,我认为有必要警告 OP,并且正确解释它对于评论来说太长了,所以我专门添加了一个答案来涵盖这个问题。


除了日志记录问题之外,您的安排还可能存在令人讨厌的竞争条件。由于脚本始终使用同一目录来暂存要存档的文件,因此如果脚本的多个实例同时运行,则第一个运行可能会删除任何后续实例当前正在处理的文件,从而导致其他故障,并且很可能是存档不完整(因为文件会在zip处理之前消失)。

可以通过以下两种方式之一解决此问题:要么脚本本身应该使用每个调用的目录,要么使用文件锁定来防止并发运行。

第一种方法更简单,您只需将日期添加到您正在使用的目录中即可。看起来会像这样(请注意,这还确保date只调用一次):

#!/bin/sh
now="$(date +%d.%m.%Y_%H.%M.%S)"
cp -r -p mnt/main-nas/PATH-TO-FILE mnt/backup-nas/01/temp/server/${now}
zip -r mnt/backup-nas/01/1.19_Test.${now}.zip mnt/backup-nas/01/temp/server/${now}
rm -r mnt/backup-nas/01/temp/server/${now}

文件锁定方法稍微复杂一些,但可以说更简洁,因为它还可以确保您不会意外地因zip同时运行多个命令而导致系统瘫痪。这涉及使用一个名为的命令flock(Ubuntu 和 Debian 上的软件包的一部分util-linux,已经安装),如下所示(带有注释来解释发生了什么):

#!/bin/sh
# All of this gets run in a subshell so we can hold a file descriptor open
# for all the commands. We're using file descriptor 9 here, but any number
# higher than 2 will work.
(
    # This flock command is what actually takes the lock. The lock itself 
    # persists until the file descriptor is closed when the subshell exits.
    # The -x means it's an exclusive lock (so only one instance can hold it).
    # The -w says to try for that many seconds before failing if something
    # else is holding the lock (this is an important safety net to ensure you
    # don’t get a long queue of these scripts waiting to run).
    # The -n indicates which file descriptor to take the lock on.
    flock -x -w 30 -n 9 || exit 1
    cp -r -p mnt/main-nas/PATH-TO-FILE mnt/backup-nas/01/temp/server
    zip -r mnt/backup-nas/01/1.19_Test.`date +%d.%m.%Y_%H.%M.%S`.zip mnt/backup-nas/01/temp/server
    rm -r mnt/backup-nas/01/temp/server
# And this line closes the subshell, and also sets the path to be used for
# the lock file by opening it as file descriptor 9 for the subshell. /run
# is generally the place you want to put stuff like this, because it will
# get cleaned up automatically every time the system reboots.
) 9> /run/backup-nas.lock

相关内容