我的 crontab 中有一个命令来监视服务(具体来说,检查我的网站的 Tor 版本是否仍然可以访问):如果可以访问该站点,则该监视命令成功,否则失败(我会收到一封电子邮件)。然而,由于 Tor 间歇性故障,我时不时地收到电子邮件,而且停机时间相当短。
如果我的 crontab 中的此监控命令连续多次(例如 10 次)失败,我希望收到通知,因此只有较长时间的中断才会通知我。
当然,我可以编写一个自定义脚本来执行此操作,将失败次数存储在临时文件等中,但由于这看起来是一个非常常见的需求,我认为可能已经存在一些标准解决方案(在同一个文件中)那样更多实用程序'chronic
已经存在以服务于类似但不同的目的。)
是否有一个包装器脚本,使得发出wrapper COMMAND
将运行COMMAND
并成功,除非最后 10 次调用COMMAND
失败,在这种情况下,它应该返回最后一个错误代码和失败调用的输出?
答案1
以下脚本可以用作您描述的包装器。它将给定命令的标准输出和标准错误流保存到状态目录 ( $HOME/states
),并存储失败运行的次数。
如果命令运行失败的次数超过 10(或为命令行标志指定的任何数字-t
),它将提供一些输出(在其标准错误流上)。在所有其他情况下,将不提供任何输出。该脚本以与给定命令相同的退出状态退出。
使用示例:
$ sh ./script.sh -t 2 sh -c 'echo "this will fail"; cd /nowhere'
$ sh ./script.sh -t 2 sh -c 'echo "this will fail"; cd /nowhere'
FAILED 2 times: sh -c echo "this will fail"; cd /nowhere
f88eff95bba49f6dd35a2e5ba744718d
stdout --------------------
this will fail
stderr --------------------
sh: cd: /nowhere - No such file or directory
END
脚本本身(依赖md5sum
于 GNU coreutils):
#!/bin/sh
statedir="$HOME/states"
if ! mkdir -p "$statedir"; then
printf 'Failed creating "%s"\n' "$statedir" >&2
exit 1
fi
max_tries=10
while getopts 't:' opt; do
case "$opt" in
t) max_tries=$OPTARG ;;
*) echo 'error' >&2
exit 1
esac
done
shift "$(( OPTIND - 1 ))"
hash=$( printf '%s\n' "$@" | md5sum | cut -d ' ' -f 1 )
"$@" >"$statedir/$hash".out 2>"$statedir/$hash".err
code=$?
if [ -f "$statedir/$hash" ]; then
read tries <"$statedir/$hash"
else
tries=0
fi
if [ "$code" -eq 0 ]; then
echo 0 >"$statedir/$hash"
exit 0
fi
tries=$(( tries + 1 ))
printf '%d\n' "$tries" >"$statedir/$hash"
if [ "$tries" -ge "$max_tries" ]; then
cat >&2 <<END_MESSAGE
FAILED $tries times: $@
stdout --------------------
$(cat "$statedir/$hash".out)
stderr --------------------
$(cat "$statedir/$hash".err)
END
END_MESSAGE
fi
exit "$code"