Erro ao comparar inteiros de ponto decimal no script bash

0

Estou tentando criar um script para acionar uma ação / alerta para um dispositivo Linux quando a média de carga atingir um limite específico.

O script é assim:

!/bin/bash

load='echo $(cat /proc/loadavg | awk '{print $2}')'
if [ "$load" -gt 5 ]; then
        echo "foo alert!"
fi

echo "System Load $(cat /proc/loadavg)"

Agradecemos a helloacm.com por me iniciar aqui.

Quando eu executo, recebo um erro:

./foocheck.sh: line 4: [: 0.03: integer expression expected

O que faz sentido - é ver o período / decimal e pensar que estou comparando uma string com um inteiro.

A maioria das soluções que encontrei envolvem bc -l , o que não está disponível neste appliance. Eu preciso encontrar uma maneira de comparar esses valores sem usar bc . Alguma ideia?

    
por Mike B 19.06.2017 / 21:11

7 respostas

1
set -- $(cat /proc/loadavg)
load=${2/./}
if [ "$load" -ge 500 ]; then
  echo alert
fi

Obtenha a média de carga de / proc e defina os parâmetros posicionais com base nesses campos. Pegue o segundo campo e retire o período. Se esse valor (agora numérico) for maior ou igual a 500, alerta. Isso pressupõe o comportamento (atual) em que as médias de carga são apresentadas em dois pontos decimais. Agradecemos a Arrow por apontar uma maneira melhor.

    
por 19.06.2017 / 22:50
2

Você só pode usar uma parte inteira para comparar:

load=$(awk '{print $2}' /proc/loadavg | cut -d. -f1)
    
por 19.06.2017 / 21:28
2

Como você tem o awk disponível e o awk pode processar valores de ponto flutuante, faça:

awk '($1>5){print("yes")}'

Roteiro editado:

#!/bin/bash

load='echo $(cat /proc/loadavg | awk '{print $2}')'
loadtest=$(echo "$load" | awk '($1>5){print("yes")}')
if [ "$loadtest" = yes ]; then
    echo "foo alert!"
fi

é claro, todo o script pode ser simplificado usando apenas o awk.

Talvez:

#!/bin/bash
awk '($2>5){print("foo alert!")}' /proc/loadavg
    
por 19.06.2017 / 21:48
1

Resposta curta: você não pode fazer isso. Na verdade, bash não pode fazer isso, embora você, o humano, possa fazer isso muito bem. Consulte link para obter mais detalhes.

    
por 19.06.2017 / 21:16
1

bash não pode fazer pontos flutuantes. Use zsh , ksh93 ou yash :

#! /bin/zsh -
read ignore load ignore < /proc/loadavg || exit
if ((load > 5)); then
  echo >&2 Alert
fi

Ou já que você está usando awk (com alguns comandos desnecessários):

#! /bin/sh -
awk '$2 > 5 {print "Alert"}' < /proc/loadavg >&2

Ou se você precisar de um sh if construct:

#! /bin/sh -
if awk '{exit !($2 > 5)}' < /proc/loadavg; then
  echo >&2 Alert
fi
    
por 23.06.2017 / 21:39
0

Converter em números inteiros e em uma matriz pode ser o caminho mais curto:

!/bin/bash
# Remove decimal point (multiply by 100) and put it into an array
declare -a load=( $(tr -d . < /proc/loadavg) )
if [ ${load[0]} -gt 500 ]; then
    echo "foo alert!"
fi
echo "System Load $(cat /proc/loadavg)"
    
por 19.06.2017 / 22:54
0

Eu ainda dou crédito a @ jeff-schaller, mas pela perfeição, aqui estava a abordagem com a qual eu fui:

#!/bin/bash

#Threshold value for minimum load average necessary to trigger an alert. 
loadthreshold=30

#Admin defined value for where to send email alert
[email protected]

#Time/date for filename saving later.
logtimestamp='date +%Y-%m-%d.%H-%M-%S'

#Check the load average value for the past 5-minute time span.
load='echo $(cat /proc/loadavg | awk '{print $2}')'

#Truncate the load average value (leaving off the fractional values) and trigger an alert action if it's greater than (or equal to) the admin-defined threshold.
if [ "${load%.*}" -ge "$loadthreshold" ]; then
    echo "Yo admin, your system load average is pretty high: $load.  Check the server  " | mail -s "System load average spike detected" "$alertrecipient"
    tar cvzf "high-la-logs$logtimestamp.tar.gz" /var/log/ 
fi

A única diferença real é alavancar "${load%.*}" para cortar o material à direita do decimal.

    
por 23.06.2017 / 21:23