我想测试 cron 在执行任务之后的邮件发送以及类似的事情是否有效。有没有更优雅的方法来测试这个,然后设置一个 cron 作业每隔几秒运行一次?那么,有没有什么方法可以模拟 cron 作业的执行/手动启动 cron 作业,但具有与 cron 自动运行时相同的行为?
答案1
在命令行上执行 cron 作业和在 cron 内部执行 cron 作业的主要区别在于其环境。其他潜在的差异包括当前目录、终端的可用性以及使用的 shell。
这是通过 cron 运行 cron 作业的相当准确的模拟。为了避免由于 shell 造成的差异,请将您的作业放入脚本中,并仅将该脚本的路径放入 crontab 中。请注意,由 cron 传递的环境变量的确切设置和值取决于实现;检查crontab(5)
系统上的手册页。ifne
是一个命令,如果收到一些输入,则运行参数中指定的命令;有一个在更多实用程序。
env -i HOME="$HOME" LOGNAME="$LOGNAME" PATH=/usr/bin:/bin SHELL=/bin/sh USER="$USER" \
/path/to/script </dev/null 2>&1 |
ifne mail -r "Cron Daemon" -s "Cron <$USER@$(hostname)> /path/to/script" "$USER"
创建类似 cron 设置的另一种方法是通过at
。但at
负责使用at
进程收到的环境变量运行命令,因此您仍然需要模拟这部分。
echo /path/to/script |
env -i HOME="$HOME" LOGNAME="$LOGNAME" PATH=/usr/bin:/bin SHELL=/bin/sh USER="$USER" \
at now
答案2
以下是我如何模拟我几年前创建的脚本的 cron 执行,但该脚本最近开始失败。
我创建了一个名为的脚本dumpenv
:
#!/bin/sh
base=$(basename $0)
env -0 > /tmp/$base.$$.dump
这会将所有环境变量转储到/tmp/
.然后我修改了我的 crontab 添加:
*/1 * * * * [path to newly created script]
这使得脚本每分钟运行一次。一分钟后,我得到了从 cron 运行的任务所看到的环境转储。如果 crontab 行运行超过一分钟,它会创建一堆相同的文件,其名称仅在文件名的 pid 部分有所不同 ( $$
)。没什么大不了的。我可以针对这种可能性进行编码,以便只获取一个文件,但这里的主要原则是“足够好”,并且我可能想dumpenv
在多个转储有用的其他上下文中使用。无论如何,建议删除添加的 crontab 行,以避免填充/tmp
大量垃圾。
然后我创建了一个额外的文件,我称之为/tmp/command
其中包含我想要执行的命令,在一行上以空字符终止。空字符是必需的。
然后我发出:
cat [path to dumpfile crated earlier] /tmp/command | xargs -0 -x env -i
这复制了我从 cron 执行命令时看到的错误。所做xargs
的是构建以下形式的命令:
env -i [list of environment variables] [command to execute]
并执行它。环境变量列表来自转储文件。执行的命令env
来自/tmp/command
文件。
我上面提到的and-0
的参数以及所需的空字符是为了防止在传递变量时发生环境破坏。如果环境不包含带有换行符的环境变量,则可以从脚本和命令的调用中省略,并且文件不需要空字符作为行终止符。env
xargs
-0
env
dumpenv
xargs
/tmp/command
我没有将 stdin 显式重定向到 /dev/null 因为 xargs 为我做了它。我也不关心重定向 stdout/stderr,并且我不想在命令失败时收到电子邮件。对于需要这些功能的情况,吉尔斯的答案提供了实现它的方法。
答案3
路易斯的回答是很棒的。我提出了一些可能的改进。
/tmp/command
不要像 Louis 在以下代码中建议的那样创建包含要执行的脚本路径的文件:
cat [path to dumpfile crated earlier] /tmp/command | xargs -0 -x env -i
相反,您可以通过以下备用命令直接在命令中命名脚本(请注意\x00
附加到 cron 脚本路径,这是必不可少的:
printf "/path/to/cron/script\x00" | cat /path/to/dumpfile/created/earlier - | xargs -0 -x env -i
这避免了创建文件的需要/tmp/command
。