我有一个计划每天运行的 cron 作业,除了更改计划之外,还有其他方法可以立即测试该命令以查看它是否按预期运行吗?
编辑:(从评论中)我知道该命令在 shell(我的 shell)中输入时工作正常,但我想知道 cron 运行它时它是否正常工作,它可能会受到 ENV 或 shell 特定内容的影响(〜扩展)或所有权和许可的东西或......
答案1
您可以使用以下命令强制 crontab 运行:
run-parts /etc/cron.daily
答案2
您可以模拟 cron 用户环境,如中所述“立即手动运行 cron 作业”。这将允许您测试作业以 cron 用户身份运行时的工作情况。
摘自链接:
步骤1:我将这一行暂时放在用户的 crontab 中:
* * * * * /usr/bin/env > /home/username/tmp/cron-env
然后在文件写入后将其取出。
第2步:自己制作了一个 run-as-cron bash 脚本,其中包含:
#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"
那么,作为有问题的用户,我能够
run-as-cron /the/problematic/script --with arguments --and parameters
答案3
据我所知,没有办法直接做到这一点,因为 cron 有一个特殊的目的 - 在特定时间运行计划命令。因此,最好的办法是手动创建一个(临时)crontab 条目或编写一个删除并重置环境的脚本。
“删除并重置环境”的说明:
可以启动包装器脚本(这会删除环境),该脚本将在启动脚本之前env -i
获取已保存的环境(确保导出所有变量,可能首先进行设置)。set -a
保存的环境将是 cron 作业的默认环境,通过作为 cronjob运行env
(或取决于 cron 作业使用的 shell)来记录,并保存其输出。declare -p
答案4
在需要自己调试 cron 作业后,我编写了以下脚本。在运行命令之前,它会尽力模拟与 cron 完全相同的条件(包括修改的环境,但它也与非交互式 shell、无附加终端等有关)。
使用您的命令/脚本作为参数调用它,您可以立即轻松地调试您的 cron 作业。它还托管(并可能更新)在 GitHub 上:run-as-cron.sh
:
#!/bin/bash
# Run as if it was called from cron, that is to say:
# * with a modified environment
# * with a specific shell, which may or may not be bash
# * without an attached input terminal
# * in a non-interactive shell
function usage(){
echo "$0 - Run a script or a command as it would be in a cron job," \
"then display its output"
echo "Usage:"
echo " $0 [command | script]"
}
if [ "$1" == "-h" -o "$1" == "--help" ]; then
usage
exit 0
fi
if [ $(whoami) != "root" ]; then
echo "Only root is supported at the moment"
exit 1
fi
# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
echo "Unable to find $cron_env"
echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
exit 0
fi
# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
env_string="${env_string} $envi "
done
cmd_string=""
for arg in "$@"; do
cmd_string="${cmd_string} \"${arg}\" "
done
# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"
# Let's redirect the output into files
# and provide /dev/null as input
# (so that the command is executed without an open terminal
# on any standard file descriptor)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" > "$so" 2> "$se" < /dev/null
echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"