测试每周的 cron 作业 [关闭]

Posted

技术标签:

【中文标题】测试每周的 cron 作业 [关闭]【英文标题】:Test a weekly cron job [closed] 【发布时间】:2011-06-26 11:08:25 【问题描述】:

我在 cron.week 目录中有一个 #!/bin/bash 文件。

有没有办法测试它是否有效?等不及 1 周

我在 Debian 6 上使用 root

【问题讨论】:

你不能通过在命令行上运行脚本来测试它吗? 只需在您的crontab 中添加一个单独的条目,每隔几分钟运行您的文件,看看是否有预期的结果,然后从您的 crontab 中删除测试条目。试试crontab -e 不,从命令行运行它不是一个好方法。仅从命令行运行脚本并不能保证它甚至会像从 cron 运行时一样运行。即使它确实以同一用户身份运行,您也永远无法确定其他一切是否相同。从命令行运行的脚本在从 cron 运行时可能会因所有各种原因而失败。 "all sorts" 可能有点夸张...权限和环境变量是我想到的两个,但是你可以很容易地拥有不同的其他初始条件,比如别名 我刚刚测试了一个新的 cron 作业,我将在“各种”中添加另一个项目。如果您在 bash_profile 中有东西,它们不会在 cron 作业中运行一次,而从命令行测试作业可以完美运行。在标准命令行上测试 cron 作业根本不是一个好的测试。 【参考方案1】:

有点超出你的问题范围......但这就是我所做的。

“我如何测试 cron 作业?”问题与“如何测试在其他程序启动的非交互式上下文中运行的脚本?”密切相关。在 cron 中,触发器是一些时间条件,但许多其他 *nix 工具以非交互方式启动脚本或脚本片段,并且这些脚本运行的条件通常包含意外的内容并导致损坏,直到错误被解决。 (另见:https://***.com/a/17805088/237059)

解决这个问题的一般方法很有帮助。

我最喜欢的技术之一是使用我编写的名为“crontest”的脚本。它在 cron 中的 GNU 屏幕会话中启动目标命令,这样您就可以连接一个单独的终端以查看发生了什么,与脚本交互,甚至使用调试器。

要进行设置,您可以在 crontab 条目中使用“all stars”,并将 crontest 指定为命令行上的第一个命令,例如:

* * * * * crontest /command/to/be/tested --param1 --param2

所以现在 cron 将每分钟运行一次您的命令,但 crontest 将确保一次只运行一个实例。如果命令需要时间运行,您可以执行“screen -x”来附加并观察它运行。如果命令是脚本,你可以在顶部放一个“读取”命令让它停止并等待屏幕附件完成(附加后按回车)

如果你的命令是一个 bash 脚本,你可以这样做:

* * * * * crontest --bashdb /command/to/be/tested --param1 --param2

现在,如果您使用“screen -x”附加,您将面临一个交互式 bashdb 会话,您可以单步执行代码、检查变量等。

#!/bin/bash

# crontest
# See https://github.com/Stabledog/crontest for canonical source.

# Test wrapper for cron tasks.  The suggested use is:
#
#  1. When adding your cron job, use all 5 stars to make it run every minute
#  2. Wrap the command in crontest
#        
#
#  Example:
#
#  $ crontab -e
#     * * * * * /usr/local/bin/crontest $HOME/bin/my-new-script --myparams
#
#  Now, cron will run your job every minute, but crontest will only allow one
#  instance to run at a time.  
#
#  crontest always wraps the command in "screen -d -m" if possible, so you can
#  use "screen -x" to attach and interact with the job.   
#
#  If --bashdb is used, the command line will be passed to bashdb.  Thus you
#  can attach with "screen -x" and debug the remaining command in context.
#
#  NOTES:
#   - crontest can be used in other contexts, it doesn't have to be a cron job.
#       Any place where commands are invoked without an interactive terminal and
#       may need to be debugged.
#
#   - crontest writes its own stuff to /tmp/crontest.log
#
#   - If GNU screen isn't available, neither is --bashdb
#

crontestLog=/tmp/crontest.log
lockfile=$(if [[ -d /var/lock ]]; then echo /var/lock/crontest.lock; else echo /tmp/crontest.lock; fi )
useBashdb=false
useScreen=$( if which screen &>/dev/null; then echo true; else echo false; fi )
innerArgs="$@"
screenBin=$(which screen 2>/dev/null)

function errExit 
    echo "[-err-] $@" | tee -a $crontestLog >&2


function log 
    echo "[-stat-] $@" >> $crontestLog


function parseArgs 
    while [[ ! -z $1 ]]; do
        case $1 in
            --bashdb)
                if ! $useScreen; then
                    errExit "--bashdb invalid in crontest because GNU screen not installed"
                fi
                if ! which bashdb &>/dev/null; then
                    errExit "--bashdb invalid in crontest: no bashdb on the PATH"
                fi

                useBashdb=true
                ;;
            --)
                shift
                innerArgs="$@"
                return 0
                ;;
            *)
                innerArgs="$@"
                return 0
                ;;
        esac
        shift
    done


if [[ -z  $sourceMe ]]; then
    # Lock the lockfile (no, we do not wish to follow the standard
    # advice of wrapping this in a subshell!)
    exec 9>$lockfile
    flock -n 9 || exit 1

    # Zap any old log data:
    [[ -f $crontestLog ]] && rm -f $crontestLog

    parseArgs "$@"

    log "crontest starting at $(date)"
    log "Raw command line: $@"
    log "Inner args: $@"
    log "screenBin: $screenBin"
    log "useBashdb: $( if $useBashdb; then echo YES; else echo no; fi )"
    log "useScreen: $( if $useScreen; then echo YES; else echo no; fi )"

    # Were building a command line.
    cmdline=""

    # If screen is available, put the task inside a pseudo-terminal
    # owned by screen.  That allows the developer to do a "screen -x" to
    # interact with the running command:
    if $useScreen; then
        cmdline="$screenBin -D -m "
    fi

    # If bashdb is installed and --bashdb is specified on the command line,
    # pass the command to bashdb.  This allows the developer to do a "screen -x" to
    # interactively debug a bash shell script:
    if $useBashdb; then
        cmdline="$cmdline $(which bashdb) "
    fi

    # Finally, append the target command and params:
    cmdline="$cmdline $innerArgs"

    log "cmdline: $cmdline"


    # And run the whole schlock:
    $cmdline 

    res=$?

    log "Command result: $res"


    echo "[-result-] $(if [[ $res -eq 0 ]]; then echo ok; else echo fail; fi)" >> $crontestLog

    # Release the lock:
    9<&-
fi

【讨论】:

太棒了,完美的解决方案。我尝试过的所有其他技术都没有真正奏效,crontest 轻松解决了这个问题。 这比我需要的要多,但无论如何 +1 是一个很好的解决方案;将 cron 设置为更频繁地运行并将输出转储到 /tmp 足以发现我的问题。 酷。是的,如果您只需要一把铲子,就没有理由启动推土机 :) 好东西。在mac上注意我必须brew tap discoteq/discoteq; brew install flock然后修改脚本以使用/usr/local/bin/flock 不错的实用程序!对于诊断非交互式上下文中的身份验证问题非常有用。【参考方案2】:

做 cron 做的事,以root 运行以下命令:

run-parts -v /etc/cron.weekly

...如果您收到“不是目录:-v”错误,则下一个:

run-parts /etc/cron.weekly -v

选项-v 在运行之前打印脚本名称。

【讨论】:

如果我使用 -v 选项它显示“不是目录:-v”错误,我的系统中没有此命令的手册页,-v 表示详细,对吗?我正在使用 centos 6.4 为了避免“不是目录”错误,我不得不这样做:run-parts /etc/cron.weekly -v 但这并没有考虑到可以在crontab中设置的环境变量 run-parts 只是运行给定目录的脚本。与 cron 无关。 这真的不应该被赞成和接受,除了运行脚本之外,它并没有告诉你脚本在从 cron 运行时是否真的可以工作。在此问题的其他答案之一中使用出色的 crontest 脚本。【参考方案3】:

我使用Webmin 是因为它对于那些发现命令行管理有点令人生畏和难以理解的人来说是一个生产力宝石。

“系统 > 计划的 Cron 作业 > 编辑 Cron 作业”网页界面中有一个“保存并立即运行”按钮。

它显示了命令的输出,这正是我所需要的。

【讨论】:

【参考方案4】:

我使用的解决方案如下:

    编辑 crontab(使用命令 :crontab -e)以频繁运行作业 根据需要(每 1 分钟或 5 分钟) 修改应该使用 cron 执行的 shell 脚本以将输出打印到某个文件中(例如:echo "Working fine" >> 输出.txt) 使用以下命令检查 output.txt 文件:tail -f output.txt,该命令会将最新添加的内容打印到该文件中,从而您可以跟踪脚本的执行情况

【讨论】:

【参考方案5】:

这些答案都不适合我的具体情况,即我想运行一个特定的 cron 作业,只运行一次,然后立即运行。

我在 Ubuntu 服务器上,我使用 cPanel 来设置我的 cron 作业。

我只是写下了我当前的设置,然后将它们编辑为从现在开始的一分钟。当我修复另一个错误时,我只是从现在开始一分钟后再次编辑它。当我全部完成后,我只是将设置重置为之前的状态。

示例:现在是下午 4:34,所以我输入 35 16 * * *,让它在 16:35 运行。

它就像一个魅力,我不得不等待的时间最多不到一分钟。

我认为这是比其他一些答案更好的选择,因为我不想运行所有每周的 crons,也不想每分钟都运行该作业。在我准备好再次测试之前,我需要几分钟来解决问题。希望这对某人有所帮助。

【讨论】:

为什么要使用 cron 来“只运行一次,然后立即运行”?听起来你最好直接运行脚本。【参考方案6】:
sudo run-parts --test /var/spool/cron/crontabs/

crontabs/ 目录中的文件需要可由所有者执行 - 八进制 700

来源:man cronNNRooth's

【讨论】:

两次。第一:要以 sudo 的方式运行,使用不同的环境(定义的变量)。因此,您的 crontab 中的错误可以在以“sudo”执行时起作用,但在以“root”执行时不起作用(反之亦然)。第二:'man cron' 没有向我显示这个信息(好吧,我的 man 似乎是 debian-specific)......'man run-parts' 说 --test 不运行脚本,而只打印他们。所以脚本甚至没有经过测试。一件小事:'可由所有者执行':据我所知,cronjobs 仅以 root 身份执行。 @Alex As far as I know, cronjobs only are executed as root. - 取决于。在上面提到的目录中,每个用户都可以有一个 crontab,它们将作为创建它们的用户执行。 /etc/cron.d 中的 Cronjobs 始终需要指定用户作为他们运行的对象(请参阅 man cron)。【参考方案7】:

在弄乱了 cron 中一些不能立即兼容的东西后,我发现以下方法非常适合调试:

crontab -e

* * * * * /path/to/prog var1 var2 &>>/tmp/cron_debug_log.log

这将每分钟运行一次任务,您只需查看/tmp/cron_debug_log.log 文件即可了解发生了什么。

这并不完全是您可能正在寻找的“解雇工作”,但这在调试最初无法在 cron 中运行的脚本时帮助了我很多。

【讨论】:

我会推荐这种方法。大多数情况下的问题是您看不到错误。 行不正确,并非任何发行版都将 bash 用于 cron shell,因此 &>> 不起作用。我建议改用&gt;&gt;/tmp/cron_debug_log.log 2&gt;&amp;1 /path/to/prog 是什么意思——哪个编? 您要使用 cron 运行的程序。这可以是usr/home/myFancyScript.sh,也可以是简单的ls,或者任何你想定期运行的东西。 这对我有用。这是进行快速测试以检查一切是否正常的最简单方法【参考方案8】:

我通常通过运行我这样创建的作业进行测试:

使用两个终端更容易做到这一点。

运行作业:

#./jobname.sh

前往:

#/var/log and run 

运行以下命令:

#tailf /var/log/cron

这让我可以实时查看 cron 日志更新。运行后也可以查看日志,我更喜欢实时观看。

这是一个简单的 cron 作业的示例。运行 yum 更新...

#!/bin/bash
YUM=/usr/bin/yum
$YUM -y -R 120 -d 0 -e 0 update yum
$YUM -y -R 10 -e 0 -d 0 update

这是细分:

第一个命令将更新 yum 本身,接下来将应用系统更新。

-R 120 : 设置 yum 在执行命令前等待的最长时间

-e 0 :将错误级别设置为 0(范围 0 - 10)。 0 表示仅打印必须告知您的严重错误。

-d 0 :将调试级别设置为 0 - 增加或减少打印的内容数量。 (范围:0 - 10)。

-y :假设是;假设任何问题的答案都是肯定的

构建 cron 作业后,我运行以下命令以使我的作业可执行。

#chmod +x /etc/cron.daily/jobname.sh 

希望这会有所帮助, 多拉克

【讨论】:

【参考方案9】:

除此之外你还可以使用:

http://pypi.python.org/pypi/cronwrap

结束您的 cron,以便在成功或失败时向您发送电子邮件。

【讨论】:

Cron 执行时不是已经通过电子邮件发送和输出脚本了吗? Cron 向用户发送电子邮件,通常大多数 cron 作业的用户要么是 root 用户,要么是仅非交互式服务用户,因此您永远不会看到电子邮件。当错误触发大量电子邮件并退回到根目录时,这就是服务器被填满的方式。【参考方案10】:

我会使用锁定文件,然后将 cron 作业设置为每分钟运行一次。 (使用 crontab -e 和 * * * * * /path/to/job)这样您就可以继续编辑文件,并且每分钟都会对它们进行测试。此外,您只需触摸锁定文件即可停止 cronjob。

    #!/bin/sh
    if [ -e /tmp/cronlock ]
    then
        echo "cronjob locked"
        exit 1
    fi

    touch /tmp/cronlock
    <...do your regular cron here ....>
    rm -f /tmp/cronlock

【讨论】:

你也可以在shell中使用flock(1);见man 1 flock。由于它提供自动阻塞,因此非常适合此类用途。【参考方案11】:

将其放入cron.hourly,等到下一次每小时运行的 cron 作业,然后将其删除如何?这将在一小时内运行一次,并在 cron 环境中运行。你也可以运行./your_script,但不会有和cron下一样的环境。

【讨论】:

这与@Cort3z 的答案几乎相同,但细节较少

以上是关于测试每周的 cron 作业 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WAMP 等本地服务器中测试 cron 作业?

@Scheduled注解cron的规则表达式

用于存储计划/cron 作业的数据库结构?

crontab

无法安装 CRON 作业 [关闭]

PHP:要求路径不适用于 cron 作业?