Script Bash corresponde à saída grep e envia mensagem

2

Estou desenvolvendo um script para verificar o status do monit para que eu possa enviar mensagens de status OK para o servidor NagiOS NSCA (verificações passivas). O problema que estou tendo é que meu script bash ainda envia mensagens se a função grep do script não incluir nada que possa disparar o envio da mensagem.

Script:

Variáveis

rsysl='rsyslog'
log='messages'

Comandos nas variáveis

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)

Comando de status de monitora

# Postfix check
$monstat

A função de envio de mensagens, como você pode ver, deve enviar a mensagem somente quando status é igual a não está em execução e não está acessível

if [ "status" == "not running" ] && [ "status" == "not accessible" ]; then
   $nsca_status
else
   :
fi

Saída grep (na situação real, o comando de envio de mensagens deve corresponder em execução e acessível :

# monit status|grep -C 1 'rsyslog'

Process 'rsyslog'
  status                            Running
--

File 'rsyslog-messages-log'
  status                            Accessible
    
por mYzk 08.07.2014 / 15:00

1 resposta

5

Na verdade, há vários problemas nos trechos que você postou. O que está sempre enviando mensagens é que a seção "Comandos em variáveis" não está fazendo o que você acha que está fazendo. Especificamente, o que var=$(command) faz é executar o comando imediatamente , depois colocar sua saída na variável. Como o comando nsca_status=$( ... | /usr/sbin/send_nsca ... ) é sempre executado, a mensagem é sempre enviada - e enviada antes da declaração if que deve decidir se deseja enviá-la ou não.

Em geral, armazenar um comando em uma variável é complicado (veja BashFAQ # 50: estou tentando colocar um comando em um variável, mas os casos complexos sempre falham! ), e geralmente uma má idéia. Em um caso como este, apenas use o comando diretamente (sem tentar armazená-lo e recuperá-lo) ou use uma função:

nsca_status() {
    echo -e "$host\t$rsysl\t0\tOK" | /usr/sbin/send_nsca -H mon.lv.lan -c /etc/send_nsca.cfg
}

(e depois executá-lo com apenas nsca_status - no $ .)

No caso dos outros dois comandos nessa seção, você provavelmente quer executá-los imediatamente e armazenar os resultados, então eles estão bem. Bem, na verdade, há um problema com monstat=$(monit status|grep -C 1 '$rsysl') - as aspas simples em torno de $rsysl impedirão que ele seja expandido como referência de variável, portanto, grep pesquisará $rsysl , em vez de rsyslog . Para corrigir isso, use aspas duplas. Referências de variáveis devem quase sempre ser agrupadas em aspas duplas. Mas note que você deve não tentar executar $monstat como um comando - que tentará executar a saída de grep ( Process 'rsyslog' status Running ... ) como se fosse um comando, que não faz sentido.

Os outros problemas que vejo estão na declaração if :

if [ "status" == "not running" ] && [ "status" == "not accessible" ]; then

... na verdade, existem 3 problemas fatais aqui (e um pequeno argumento): primeiro, está comparando a string "status" com "não em execução" e "não acessível", mas você quer para comparar a saída do comando monit status | grep ... . Isso é simples de corrigir, use "$monstat" em vez de "status" .

Em segundo lugar, a parte && significa que ela será acionada somente se ocorrerem ambas ; isto é, se algo não está rodando e algo não está acessível. Espero que você queira acionar o relatório se qualquer algo não estiver em execução ou algo não estiver acessível, então use || .

Terceiro, você está fazendo testes de igualdade de strings; ou seja, você está verificando se o relatório inteiro consiste em "não está em execução" e nada mais . Tenho certeza que você quer ver se contém "não está em execução" ou "não está acessível". Você pode fazer isso com a expressão condicional mais avançada do bash ( [[ ]] em vez de [ ] ), que permite correspondências curinga:

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

... onde os curingas ( * ) correspondem ao que quer que seja antes de & depois da string em questão. BTW, observe que também usei = em vez de == - na verdade, é mais comum em scripts de shell. Outra opção seria usar grep para fazer a correspondência:

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

observe que não há [ ] ou [[ ]] aqui; a instrução if examina se o comando foi bem-sucedido ou não, e grep é bem-sucedido apenas se encontrar uma correspondência. A parte -q diz a grep para não imprimir a correspondência que encontrar - não queremos ver a correspondência, apenas para saber se houve uma.

Na verdade, ocorre-me que pode haver um quarto problema sério: monit status capitaliza suas mensagens de status? Isso é importante porque "Não está em execução" (ou "Não está em execução") não corresponderá a "não está em execução". Se estiver em maiúscula, deve-se capitalizar a string de pesquisa da mesma maneira ou fazer uma pesquisa de caso inteligente com [[ "$monstat" = *[nN]"ot "[rR]"unning"* ]] ou a opção -i do grep.

Ah, e uma nota final: se você não precisa de uma cláusula else , apenas deixe de fora. Não é necessário ter um vazio com o comando : pseudo.

De qualquer forma, com todas essas alterações, aqui está o que recebo para o script inteiro:

#!/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

EDIT: Eu acho que pode ter entendido mal o sentido do teste; é suposto para enviar os dados, se tudo estiver OK? Eu estava assumindo que estava enviando um status de erro e, portanto, deveria enviar somente se houvesse um problema. Se for esse o caso, use ! apropriado para inverter o sentido das correspondências. Na versão [[ ]] , use != para ver se a string não foi encontrada:

if [[ "$monstat" != *[nN]"ot "[rR]"unning"* ]] && [[ "$monstat" != *[nN]"ot "[aA]"ccessible"* ]]; then

Na versão do grep, um único ! inverte todo o teste if :

if ! echo "$monstat" | grep -E -i -q "not running|not accessible"; then
    
por 09.07.2014 / 07:34