我有一个#!/bin/bash文件。周目录。

有办法测试它是否有效吗?不能等一个星期

我在Debian 6上使用root


当前回答

有点超出了你的问题范围……但我是这么做的

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

有一个解决这个问题的通用方法是有帮助的。

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

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

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

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

如果你的命令是一个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

其他回答

除此之外,你还可以用:

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

结束你的cron,在成功或失败时给你发一封电子邮件。

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

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

我只是写下了我的当前设置,然后将它们编辑为一分钟后的设置。当我修复另一个错误时,我只是再次编辑它到一分钟后。当我全部完成时,我只是把设置重置回以前的样子。

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

它像魔法一样有效,我所要等待的最长时间不到一分钟。

我认为这是一个比其他一些答案更好的选择,因为我不想运行所有的每周cron,也不想让工作每分钟都运行。在我准备再次测试之前,我花了几分钟时间来修复任何问题。希望这能帮助到一些人。

我之所以使用Webmin,是因为对于那些觉得命令行管理有点令人生畏和难以理解的人来说,它是一种生产力的宝石。

在“System > Scheduled Cron Job > Edit Cron Job”web界面中有一个“保存并立即运行”按钮。

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

有点超出了你的问题范围……但我是这么做的

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

有一个解决这个问题的通用方法是有帮助的。

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

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

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

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

如果你的命令是一个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

我通常通过运行我创建的作业来测试,就像这样:

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

运行工作:

#./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 

希望这能有所帮助, Dorlack