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