我正在开发一个用于 monit 状态检查的脚本,以便我可以向 NagiOS NSCA 服务器发送 OK 状态消息(被动检查)。我遇到的问题是,如果脚本 grep 函数不包含任何会触发消息发送的内容,我的 bash 脚本仍会发送消息。
脚本:
变量
rsysl='rsyslog'
log='messages'
变量中的命令
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
消息发送函数,如你所见,它只在以下情况下发送消息地位等于没有运行和无法访问
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
答案1
您发布的摘录中实际上存在一些问题。导致它总是发送消息的原因是“变量中的命令”部分没有按照您的想法执行。具体来说,它所做的var=$(command)
是立即执行命令,然后将其输出在变量中。由于nsca_status=$( ... | /usr/sbin/send_nsca ... )
命令始终会被执行,因此消息始终会被发送 —— 并且if
在决定是否发送消息的语句之前发送。
一般来说,将命令存储在变量中比较棘手(参见BashFAQ #50:我试图将命令放入变量中,但复杂的情况总是失败!),一般来说这不是一个好主意。在这种情况下,要么直接使用命令(而不尝试存储和检索它),要么使用函数:
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即可执行$
)
对于本节中的其他两个命令,您可能确实希望立即执行它们并存储结果,因此它们大多没问题。实际上,存在一个问题monstat=$(monit status|grep -C 1 '$rsysl')
——周围的单引号$rsysl
会阻止它扩展为变量引用,因此grep
将搜索$rsysl
,而不是rsyslog
。要解决这个问题,请改用双引号。变量引用几乎总是应该用双引号括起来。但请注意,您应该不是然后尝试$monstat
作为命令执行——它将尝试执行grep
的输出(Process 'rsyslog' status Running ...
)就好像它是一个命令一样,这是没有意义的。
我看到的其他问题如下if
:
if [ "status" == "not running" ] && [ "status" == "not accessible" ]; then
...这里实际上有 3 个致命问题(和一个小问题):首先,它比较的是细绳“status” 表示“未运行”和“不可访问”,但您希望比较命令的输出monit status | grep ...
。这很容易修复,使用"$monstat"
代替"status"
。
其次,该&&
部分意味着只有当两个都匹配发生;也就是说,如果没有运行和有些东西无法访问。我猜你会想要触发报告,如果任何一个有些东西没有运行或者某些东西无法访问,所以请使用||
。
第三,你正在做字符串相等性测试;也就是说,你正在检查整个报告是否由“未运行”组成,并且没有其他的我很确定你想看看包含“未运行”或“不可访问”。您可以使用 bash 更高级的条件表达式([[ ]]
而不是[ ]
)来实现这一点,它允许通配符匹配:
if [[ "$monstat" = *"not running"* ]] || [[ "$monstat" = *"not accessible"* ]]; then
...其中通配符 ( *
) 匹配相关字符串之前和之后的任何内容。顺便说一句,请注意,我还使用了=
而不是==
-- 它实际上在 shell 脚本中更标准。另一个选项是使用grep
进行匹配:
if echo "$monstat" | grep -E -q "not running|not accessible"; then
请注意,这里没有[ ]
或[[ ]]
;该if
语句查看命令是成功还是失败,并且grep
只有找到匹配项时才成功。该-q
部分告诉grep
不要打印它找到的任何匹配项——我们不想看到匹配项,只是想知道是否有匹配项。
实际上,我认为可能存在第四个严重问题:是否将其状态消息大写?这很重要,因为“Not running”(或“Not Running”)与“not running”不匹配。如果它大写,请以相同的方式将搜索字符串大写,或者使用或 grep选项monit status
进行区分大小写的搜索。[[ "$monstat" = *[nN]"ot "[rR]"unning"* ]]
-i
哦,最后再说一句:如果你不需要子句,就把它省略掉。伪命令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
编辑:我想我可能误解了测试的含义;如果一切正常,它是否应该发送数据?我假设它发送的是错误状态,因此只有在出现问题时才应该发送。如果是这样,请使用适当的!
's 来反转匹配的含义。在[[ ]]
版本中,使用!=
来查看字符串是否不是成立:
if [[ "$monstat" != *[nN]"ot "[rR]"unning"* ]] && [[ "$monstat" != *[nN]"ot "[aA]"ccessible"* ]]; then
在 grep 版本中,单个命令!
会反转整个if
测试:
if ! echo "$monstat" | grep -E -i -q "not running|not accessible"; then