Назад | Перейти на главную страницу

Bash-скрипт сопоставляет вывод grep и отправляет сообщение

Я разрабатываю сценарий для проверки статуса монитора, чтобы я мог отправлять сообщения о статусе OK на сервер NagiOS NSCA (пассивные проверки). Проблема, с которой я столкнулся, заключается в том, что мой сценарий bash по-прежнему отправляет сообщения, если функция grep сценария не включает ничего, что могло бы вызвать отправку сообщения.

Сценарий:

Переменные

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

На самом деле в опубликованных вами отрывках есть ряд проблем. Причина, по которой он всегда отправляет сообщения, заключается в том, что раздел «Команды в переменных» не выполняет то, что вы думаете. В частности, что 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 - нет $.)

В случае с двумя другими командами в этом разделе вы, вероятно, действительно хотите выполнить их немедленно и сохранить результаты, так что в основном они в порядке. Ну вообще-то проблема с 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 фатальных проблемы (и одна небольшая придирка): во-первых, это сравнение строка «статус» с «не запущен» и «недоступен», но вы хотите сравнить вывод monit status | grep ... команда. Это легко исправить, используйте "$monstat" вместо того "status".

Во-вторых, && часть означает, что он сработает, только если обе происходят совпадения; то есть, если что-то не работает и что-то недоступно. Я ожидал, что вы захотите вызвать отчет, если либо что-то не работает или что-то недоступно, поэтому используйте || вместо.

В-третьих, вы выполняете проверку на равенство строк; то есть вы проверяете, состоит ли весь отчет из «не запущен» и ничего больше. Я почти уверен, что ты хочешь увидеть, содержит «не работает» или «недоступен». Вы можете сделать это с помощью более продвинутого условного выражения bash ([[ ]] вместо того [ ]), что позволяет использовать подстановочные знаки:

if [[ "$monstat" = *"not running"* ]] || [[ "$monstat" = *"not accessible"* ]]; then

... где подстановочные знаки (*) соответствует тому, что находится до и после рассматриваемой строки. Кстати, обратите внимание, что я также использовал = вместо того == - на самом деле это более стандартно для сценариев оболочки. Другой вариант - использовать grep для сопоставления:

if echo "$monstat" | grep -E -q "not running|not accessible"; then

обратите внимание, что нет [ ] или [[ ]] Вот; в if оператор смотрит, была ли команда выполнена успешно или нет, и grep успешно, только если найдет совпадение. В -q часть говорит grep не печатать найденное совпадение - мы не хотим видеть совпадение, просто чтобы знать, было ли оно.

На самом деле, мне приходит в голову, что может быть четвертая серьезная проблема: monit status заглавными буквами его статусные сообщения? Это важно, потому что «Не работает» (или «Не работает») не будет соответствовать «не работает». Если это заглавные буквы, либо используйте заглавные буквы в строке поиска, либо выполните поиск без учета регистра с помощью [[ "$monstat" = *[nN]"ot "[rR]"unning"* ]] или 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

РЕДАКТИРОВАТЬ: Я думаю, что, возможно, неправильно понял смысл теста; должен ли он отправлять данные, если все в порядке? Я предполагал, что он отправляет статус ошибки и, следовательно, должен отправлять только в случае возникновения проблемы. В этом случае используйте соответствующий !чтобы перевернуть смысл матчей. в [[ ]] версия, используйте != чтобы увидеть, является ли строка не нашел:

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