我一直在开发一个脚本,该脚本可用于在 Zabbix 监控服务停止运行时自动重新启动它们。我的脚本运行得很好,但我认为它可以改进。
#!/bin/bash
zabbix_server="service zabbix-server"
zabbix_agent="service zabbix-agent"
logfile=zabbix_auto_restart.log
logfilePath=/etc/scripts/zabbix/$logfile
zabbix_server_running=0
zabbix_agent_running=0
grep_agent (){
local retval=$(ps -ef | grep -v grep | grep zabbix_agentd | wc -l)
echo $retval
}
grep_server (){
local retval=$(ps -ef | grep -v grep | grep zabbix_server | wc -l)
echo $retval
}
check_zabbix_agentd (){
if (( $(grep_agent) == 0 ))
then
$zabbix_agent start
echo `date` "$zabbix_agent was stopped... Restarting" >> $logfile
echo "************************************************" >> $logfile
#Send email to notify that the script ran
echo "$(date) $zabbix_agent was restarted from zabbix_restart.sh" | mutt -s "Zabbix Auto-restart Script Just Ran" <user email>
else
let zabbix_agent_running=1
fi
}
check_zabbix_server (){
if (( $(grep_server) == 0 ))
then
$zabbix_server start
echo `date` "$zabbix_server was stopped... Restarting" >> $logfile
echo "************************************************" >> $logfile
#Send email to notify that the script ran
echo "$(date) $zabbix_server was restarted from zabbix_restart.sh" | mutt -s "Zabbix Auto-restart Script Just Ran" <user email>
else
let zabbix_server_running=1
fi
}
main_loop (){
until ((zabbix_server_running == 1 && zabbix_agent_running == 1));
do
check_zabbix_agentd
check_zabbix_server
sleep 1.5
done
}
main_loop
答案1
你真正做错的是重复你的努力——基本上每一次硬编码的_agent
or出现_server
似乎都是完全多余的。
例如,如果这是在 Linux 系统上运行,您可以完全删除这些grep_...()
功能,并将这两个check_...
功能合并到一个实体中,其工作方式可能如下:
email(){
mutt -s "Zabbix Auto-restart Script Just Ran" \<user email\>
}
prlog(){
date +"%x %X:%tservice $1${2+%n************************}"
}
chk_run()
while [ "$#" -gt 0 ]
do if ps -C zabbix_"$1"
then : "$(($1=1))"
else set zabbix_"$@"
service "$1" start || eval >&2 '
prlog "$1 restart failed." +; exit '"$?"
prlog "$1 restarted." + >&2
prlog "$1 restarted from $0." |email
fi; shift
done
关键是您只需chk_run
使用参数列表进行调用,其中的每个成员都会向其指示每次迭代应该检查的内容。
loop()
until [ "$(($1&&$2))" -eq 1 ]
do chk_run "$@"
sleep 2
done >/dev/null 2>>"$log"
agentd=0 server=0 loop agentd server
POSIXly 唯一需要改变的是ps
命令 - 因为 POSIX 没有指定-C
开关。所以你可以将这if
一行更改为:
if ps -eocomm= |
grep -xqF zabbix_"$1"
除了mutt
、、、service
优化之外ps
,都应该是标准的命令语言。
标准语法的至少一个优点是#!/bin/bash
hash-bang 是完全不必要的 - 这里没有某些特定于 shell 的扩展的锚点,因此它在所有努力实现 POSIX 合规性的 shell 中应该几乎完全相同。这意味着这#!/bin/dash
是一个非常简单的(并且可能有效)在这种情况下进行优化。
当然,无论是否优化,这个脚本几乎总是会sleep
。
我拒绝定义$log
- 主要是因为对于你定义它的方式没有什么可说的 - 没关系 - 但你可能会想不再定义它。如果您可以确定脚本的调用环境,那么它可以成为传递参数的非常简单的方法。我的意思是,如果脚本被调用./script
并且已经可执行,那么......
log=/dev/tty ./script
...将在调用时$log
的环境中设置值。./script
我使用/dev/tty
输出文件作为示例,因为我认为您应该从它开始,同时将其调整到您满意的程度。如果将此处的代码块放入./script
并按上述方式启动,它将实时写入您的终端而不是某些输出文件 - 因此您可以清楚地了解当您的真实日志文件中会出现什么内容时你最终会这样称呼它:
log=./real/logfile ./script
或者,作为一种混合行为,您可以更改脚本,以便在它所说的地方改为2>>"$log"
:
2>>"${log:-/hardcoded/default/path/to/logfile}"
...在这种情况下,shell 将仅使用$log
尚未定义的硬编码值。这意味着:
export log=/dev/tty; ./script
log=/dev/tty ./script
...仍然会将日志文件写入终端,并且...
log= ./script
unset log; ./script
...将其写入硬编码路径,并且...
./script
$log
...将写入硬编码路径或其他位置,具体取决于是否已存在要导出到当前 shell 环境的非空值。