Bash 脚本匹配 grep 输出并发送消息

Bash 脚本匹配 grep 输出并发送消息

我正在开发一个用于 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

相关内容