Erro: expressão inteira esperada

2

Eu escrevi um script para determinar a média de carga no servidor da seguinte forma:

#!/bin/bash

loadavg='top -b -n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}''

if [ "${loadavg}" -le  1 ]
then
echo "OK - Load Average = ${loadavg} | Load_Average=${loadavg}"
exit 0;
elif [ "${loadavg}" -gt 1 ] && [ "${loadavg}" -le 2 ]
then
echo "WARNING - Load Average = ${loadavg} | Load_Average=${loadavg}"
exit 1;
elif [ "${loadavg}" -gt 2 ]
then
echo "CRITICAL - Load Average = ${loadavg} | Load_Average=${loadavg}"
exit 2;
else
echo "UNKNOWN - Load Average = NaN | Load_Average=NaN"
fi

Quando o script é executado, ele exibe o seguinte erro:

./loadavg.sh
./loadavg.sh: line 5: [:  0.06: integer expression expected
./loadavg.sh: line 9: [:  0.06: integer expression expected
./loadavg.sh: line 13: [:  0.06: integer expression expected
UNKNOWN - Load Average = NaN | Load_Average=NaN
    
por Mandar Shinde 20.06.2014 / 11:23

4 respostas

4

bash (ao contrário de ksh93 ou zsh 1 ) não pode fazer aritmética de ponto flutuante. awk pode, então você pode fazer a coisa toda em awk .

Além disso, você não precisa usar top (e esperar 1 segundo) para obter a carga. A maneira canônica de obter a carga é de uptime .

uptime | awk '{load=+$(NF-2)}
  load > 2 {print "CRITICAL: " load; exit 2}
  load > 1 {print "WARNING: " load; exit 1}
  {print "OK: " load; exit 0}
  END {if (!NR) {print "UNKNOWN"; exit 3}'
exit

1 Em zsh , você precisa usar a sintaxe (( loadavg > 2 )) em vez de [ "$loadavg" -gt 2 ] para comparar não-inteiros

    
por 20.06.2014 / 12:32
2

top -b -n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}' não retorna nada, daí os seus erros.

    
por 20.06.2014 / 11:29
2

Seu loadavg é nulo, causa erros de sintaxe em [ :

$ top -b n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}'
<blank line here>

Você deve alterá-lo para:

$ top -b n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $1}'
 0.24

No entanto, você deve usar um teste mais recente no seu script, ele pode lidar com esse problema:

$ [[ "" -gt 1 ]] || echo "OK"
OK

Com o antigo [ :

$ [ "" -gt 1 ] || echo "OK"
bash: [: : integer expression expected
OK

Atualizado

bash não pode manipular números de ponto flutuante, então sua comparação (mesmo com o novo teste [[..]] ) mostrará erros.

Você pode usar outras ferramentas para executar essa tarefa, como bc , awk ...

Exemplo:

$ [[ $(echo "3 > 1" | bc -l) == 1 ]] && echo OK
OK
$[[ $(echo "3 < 1" | bc -l) == 1 ]] || echo Not OK
Not OK
    
por 20.06.2014 / 11:29
0

Em primeiro lugar, a parte superior em execução é mais cara do que apenas pegar "tempo de atividade".

$ uptime
 16:15:38 up 6 days, 23:22, 23 users,  load average: 0.99, 0.82, 0.70

Segundo, como mencionado por Stéphane Chazelas, bash não gosta de aritmética de ponto flutuante.

$ [[ "0.1" -lt 1 ]] 
bash: [[: 0.1: syntax error: invalid arithmetic operator (error token is ".1")

Felizmente, a expansão do bash pode resolver isso. De homem bash :

   ${parameter%word}
   ${parameter%%word}
         Remove matching suffix pattern.  The word is expanded to produce a pattern just as in pathname expansion.   If
         the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is
         the expanded value of parameter with the shortest matching pattern (the ''%'' case) or  the  longest  matching
         pattern  (the  ''%%'' case) deleted.  If parameter is @ or *, the pattern removal operation is applied to each
         positional parameter in turn, and the expansion is the resultant list.  If parameter is an array variable sub-
         scripted  with  @  or *, the pattern removal operation is applied to each member of the array in turn, and the
         expansion is the resultant list.

Portanto, é muito fácil remover as partes decimais com "%. *"

$ la='uptime | sed 's/.*average: \([0-9\.]*\).*//''
$ if [ ${la%.*} -lt 1 ]; then echo "OK - Load average is $la"; fi
OK - Load average is 0.42
    
por 21.06.2014 / 01:30