我正在开发一个用于监视状态的脚本,这样我就可以向NagiOS NSCA服务器发送OK状态消息(被动检查)。 我遇到的问题是我的bash脚本仍然发送消息,如果脚本grep函数不包括任何将触发消息发送。
脚本:
variables
rsysl='rsyslog' log='messages'
variables中的命令
host=$(hostname) monstat=$(monit status|grep -C 1 '$rsysl') nsca_status=$(echo -e "$host\t$rsysl\t0\tOK" | /usr/sbin/send_nsca -H mon.lv.lan -c /etc/send_nsca.cfg)
监视状态命令
# Postfix check $monstat
消息发送function,你可以看到它只应发送消息时, 状态等于没有运行 , 不可访问
if [ "status" == "not running" ] && [ "status" == "not accessible" ]; then $nsca_status else : fi
grep输出(在实际情况下,消息发送命令必须匹配运行和可访问 :
# monit status|grep -C 1 'rsyslog' Process 'rsyslog' status Running -- File 'rsyslog-messages-log' status Accessible
您发布的摘录中实际存在一些问题。 让它总是发送消息的是“variables中的命令”部分没有做你认为正在做的事情。 具体来说, var=$(command)做的是立即执行命令 ,然后把它的输出放在variables中。 由于始终执行nsca_status=$( ... | /usr/sbin/send_nsca ... )命令,因此始终发送消息,并在应该决定是否发送该消息的if语句之前发送消息。
一般来说,将一个命令存储在一个variables中是非常棘手的(见BashFAQ#50:我试图把一个命令放在一个variables中,但是复杂的情况总是失败! ),而且通常是一个坏主意。 在这种情况下,直接使用命令(而不是试图存储和检索它),或者使用一个函数:
nsca_status() { echo -e "$host\t$rsysl\t0\tOK" | /usr/sbin/send_nsca -H mon.lv.lan -c /etc/send_nsca.cfg }
(然后用nsca_status – no $执行它。)
对于该部分中的其他两个命令,您可能确实需要立即执行它们并存储结果,所以它们大部分都是OK的。 实际上, monstat=$(monit status|grep -C 1 '$rsysl')存在一个问题 – $rsysl周围的单引号会阻止它作为variables引用扩展,所以grep将会search为$rsysl ,而不是$rsysl 。 要解决这个问题,请使用双引号。 variables引用几乎总是用双引号括起来。 但是请注意,您不应该尝试执行$monstat作为一个命令 – 它将尝试执行grep的输出( Process 'rsyslog' status Running ... ),就像它是一个命令一样,这是没有意义的。
我看到的其他问题在if语句中:
if [ "status" == "not running" ] && [ "status" == "not accessible" ]; then
……这里有三个致命的问题(和一个小问题):首先,比较string “status”与“not running”和“not accessible”,但是你想要比较monit status | grep ... monit status | grep ...命令。 这很容易解决,使用"$monstat"而不是"status" 。
其次, &&部分意味着它只会触发两个匹配发生; 也就是说,如果某些东西没有运行, 而某些东西是不可访问的。 我希望你想要触发报告,如果某个东西没有运行或某些东西不可访问,所以使用|| 代替。
第三,你正在做string相等testing; 也就是说,您正在检查整个报告是否包含“未运行”,而没有其他内容 。 我很确定你想看看它是否包含 “不运行”或“不可访问”。 你可以用bash的更高级的条件expression式( [[ ]]而不是[ ] )来做到这一点,它允许通配符匹配:
if [[ "$monstat" = *"not running"* ]] || [[ "$monstat" = *"not accessible"* ]]; then
…通配符( * )匹配string前后的任何内容。 顺便说一句,请注意,我也使用=而不是== – 它实际上在shell脚本中更为标准。 另一个select是使用grep来进行匹配:
if echo "$monstat" | grep -E -q "not running|not accessible"; then
注意这里没有[ ]或[[ ]] ; if语句会查看命令是成功还是失败,而grep只有在find匹配项时才会成功。 -q部分告诉grep不要打印它find的任何匹配 – 我们不希望看到匹配,只是为了知道是否有匹配。
实际上,我觉得可能会有第四个严重的问题: monit status利用状态信息? 这是非常重要的,因为“不运行”(或“不运行”)将不匹配“不运行”。 如果它是大写的,或者用相同的方法大写searchstring,或者用[[ "$monstat" = *[nN]"ot "[rR]"unning"* ]]或者grep的-i选项进行一个case-insentivesearch。
哦,还有一个最后的说明:如果你不需要else条款,就把它放开。 伪命令不需要有空的。
无论如何,所有这些变化是我得到的整个脚本:
#!/bin/bash # Variables rsysl='rsyslog' log='messages' # Function to send a status message nsca_status() { echo -e "$host\t$rsysl\t0\tOK" | /usr/sbin/send_nsca -H mon.lv.lan -c /etc/send_nsca.cfg } # Store output of commands host=$(hostname) monstat=$(monit status|grep -C 1 '$rsysl') # Send message if there's anything wrong if [[ "$monstat" = *[nN]"ot "[rR]"unning"* ]] || [[ "$monstat" = *[nN]"ot "[aA]"ccessible"* ]]; then nsca_status fi
编辑:我想我可能会误解testing的意义, 是否应该发送的数据,如果一切正常? 我假设它发送错误状态,因此只有在出现问题时才发送。 如果是这种情况,请使用合适的! 要颠倒比赛的感觉。 在[[ ]]版本中,使用!=查看是否找不到string:
if [[ "$monstat" != *[nN]"ot "[rR]"unning"* ]] && [[ "$monstat" != *[nN]"ot "[aA]"ccessible"* ]]; then
在grep版本中,单个! 反转整个iftesting:
if ! echo "$monstat" | grep -E -i -q "not running|not accessible"; then