mYz*_*Yzk 2 scripting bash monit
我正在开发一个用于 monit 状态检查的脚本,以便我可以将 OK 状态消息发送到 NagiOS NSCA 服务器(被动检查)。我遇到的问题是,如果脚本 grep 函数不包含任何会触发消息发送的内容,我的 bash 脚本仍会发送消息。
脚本:
变量
rsysl='rsyslog'
log='messages'
Run Code Online (Sandbox Code Playgroud)
变量中的命令
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)
Run Code Online (Sandbox Code Playgroud)
监控状态命令
# Postfix check
$monstat
Run Code Online (Sandbox Code Playgroud)
如您所见,消息发送功能仅在状态等于未运行且不可访问时发送消息
if [ "status" == "not running" ] && [ "status" == "not accessible" ]; then
$nsca_status
else
:
fi
Run Code Online (Sandbox Code Playgroud)
Grep 输出(在实际情况下,消息发送命令必须匹配运行和可访问:
# monit status|grep -C 1 'rsyslog'
Process 'rsyslog'
status Running
--
File 'rsyslog-messages-log'
status Accessible
Run Code Online (Sandbox Code Playgroud)
您发布的摘录中实际上存在许多问题。让它总是发送消息的原因是“变量中的命令”部分没有做你认为它在做的事情。具体来说,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
}
Run Code Online (Sandbox Code Playgroud)
(然后只用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
Run Code Online (Sandbox Code Playgroud)
...这里实际上有 3 个致命的问题(还有一个小问题):首先,它将字符串“状态”与“未运行”和“不可访问”进行比较,但您想比较monit status | grep ...命令的输出。这很容易修复,使用"$monstat"而不是"status".
其次,这&&部分意味着只有当两个匹配都发生时才会触发;也就是说,如果某些东西没有运行并且某些东西不可访问。我希望你会想要触发如果报告或者有什么地方不运行或东西是无法访问的,所以使用||来代替。
第三,你在做字符串相等性测试;也就是说,您正在检查整个报告是否包含“未运行”,而没有其他内容。我很确定您想查看它是否包含“未运行”或“无法访问”。您可以使用 bash 更高级的条件表达式([[ ]]而不是[ ])来执行此操作,它允许通配符匹配:
if [[ "$monstat" = *"not running"* ]] || [[ "$monstat" = *"not accessible"* ]]; then
Run Code Online (Sandbox Code Playgroud)
...其中通配符 ( *) 匹配相关字符串之前和之后的任何内容。顺便说一句,请注意,我还使用了=而不是==-- 它实际上在 shell 脚本中更标准。另一种选择是用于grep进行匹配:
if echo "$monstat" | grep -E -q "not running|not accessible"; then
Run Code Online (Sandbox Code Playgroud)
请注意,没有[ ]或[[ ]]在这里;该if语句查看命令是成功还是失败,并且grep仅在找到匹配项时才成功。该-q部分告诉grep不要打印它找到的任何匹配项——我们不想看到匹配项,只是想知道是否有匹配项。
实际上,我想到可能存在第四个严重问题:是否将monit status其状态消息大写?这很重要,因为“未运行”(或“未运行”)与“未运行”不匹配。如果它是大写的,要么以相同的方式将搜索字符串大写,要么使用[[ "$monstat" = *[nN]"ot "[rR]"unning"* ]]or 或 grep 的-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
Run Code Online (Sandbox Code Playgroud)
编辑:我想我可能误解了测试的意义;如果一切正常,是否应该发送数据?我假设它正在发送错误状态,因此只有在出现问题时才应该发送。如果是这种情况,请使用适当的!'s 来反转匹配的含义。在[[ ]]版本,使用!=,看是否该字符串未找到:
if [[ "$monstat" != *[nN]"ot "[rR]"unning"* ]] && [[ "$monstat" != *[nN]"ot "[aA]"ccessible"* ]]; then
Run Code Online (Sandbox Code Playgroud)
在 grep 版本中,单个!反转整个if测试:
if ! echo "$monstat" | grep -E -i -q "not running|not accessible"; then
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2233 次 |
| 最近记录: |