Błąd skryptu Bash: oczekiwane wyrażenie całkowite

13

Mam dość dziwny problem, uruchamiam skrypt (Bash) na wielu serwerach i przestał on działać na jednym z serwerów (działa idealnie na wszystkich innych serwerach).

Oto część problemu w skrypcie: (nie napisałem go sam, wszystkie napisy trafiają do „Rich”) ( http://www.notrainers.org/monitoring-memory-usage-on-linux-with-nagios- i-nrpe / )

    if [ "$result" -lt "$warn_level" ]; then     #Line 56
    echo "Memory OK. $result% used."
    exit 0;
elif [ "$result" -ge "$warn_level" ] && [ "$result" -le "$critical_level" ]; then  #Line 59
    echo "Memory WARNING. $result% used."
    exit 1;
elif [ "$result" -gt "$critical_level" ]; then   #Line 62
    echo "Memory CRITICAL. $result% used."
    exit 2;
fi

Pełny komunikat o błędzie:

./check_memory.sh: Line 56: [: 7.: integer expression expected

./check_memory.sh: Line 59: [: 7.: integer expression expected

./check_memory.sh: Line 62: [: 7.: integer expression expected

Jeśli potrzebujesz więcej informacji, daj mi znać, a ja postaram się je jak najszybciej dostarczyć.

Doceń wszystkie dane wejściowe :)

Adalsteinn
źródło

Odpowiedzi:

5

Z podanego linku widzę poniższy wiersz.

result=$(echo "$used / $total * 100" |bc -l|cut -c -2)

Zgodnie z komentarzem @ Graeme zmień powyższą linię na niższą.

result=$(echo "$used / $total * 100" |bc -l)

Teraz, po dodaniu powyższego wiersza, musimy zmienić wyjście resultna liczbę całkowitą, jak poniżej.

result1=${result/.*}

Myślę, że w jednym z komputerów, na których występuje błąd, to wyjście nie jest liczbą całkowitą. Wystarczy przekonwertować wynik wyniku na liczbę całkowitą, aby można było obsłużyć takie przypadki. Dodaj poniższy wiersz po obliczeniu result.

result1=${result/.*}

I zamiast resultzmieniać nazwy zmiennych jak result1wewnątrz ifpętli, błąd się nie pojawi.

Podejrzewam, że cut -c -2atrybuty błędu wynikają głównie z tego, że wycina on tylko pierwsze 2 znaki. Co jeśli wynik ma tylko jedną postać? Załóżmy, że jeśli wynik jest 1.23456, powyższe cięcie spowoduje, 1.że wartość, dla resultktórej oczywiście jest przyczyną integer expectedbłędu.

Powodem, dla którego działa dobrze na pozostałych serwerach, jest to, że nie napotkał przypadku, w którym resultzmienna ma tylko jedną cyfrę. Jest wysoce prawdopodobne, że zawiedzie także na pozostałych serwerach, jeśli wynikiem będzie zmienna jednocyfrowa (coś takiego jak wspomniałem w powyższym przykładzie).

Ramesh
źródło
${result%%.*}byłoby poprawnym rozwinięciem, aby usunąć tutaj przecinek dziesiętny. Pamiętaj jednak, że cut -c -2spowoduje to również problemy z liczbą 100 lub więcej, więc bezpieczniej jest całkowicie ją upuścić.
Graeme
@Graeme, tęskniłem za tym. Powinienem był dokonać zmian w tym wierszu :)
Ramesh
6

Wygląda na to, że twoja resultzmienna ma w sobie znak .po tym, że bash nie rozpoznaje go jako takiego. Możesz odtworzyć błąd, wykonując po prostu:

[ 7. -gt 1 ]

Jeśli dodasz więcej skryptu do swojego pytania, | mogę zasugerować, skąd to może pochodzić.

Aktualizacja

Patrząc na pełny skrypt, po prostu zastąpiłbym wiersz:

result=$(echo "$used / $total * 100" |bc -l|cut -c -2)

Z:

result=$(( 100 * used / total ))

Ponieważ usedi totalsą liczbami całkowitymi i bashwykonują arytmetykę liczb całkowitych, należy jednak pamiętać, że przesunięcie mnożenia wynosi 100 na początek. Lub jeśli chcesz zapewnić prawidłowe zaokrąglanie („dzielenie liczb całkowitych” w obliczeniach zawsze skutecznie zaokrągla w dół):

result=$( printf '%.0f' $(echo "$used / $total * 100" | bc -l) )

Zapewni to, że nie będzie żadnych końcowych kropek result. Zastosowanie podejścia cutnie jest zbyt dobrym pomysłem, ponieważ jest ważne tylko dla wyniku z zakresu 10–99. Nie powiedzie się to resultod 0-9 (jak w twoim przypadku), a także liczb powyżej 99.

Aktualizacja 2

Z komentarza @ Stephane poniżej , lepiej zaokrąglić w dół, porównując do progów. Biorąc to pod uwagę, istnieje kolejny mały błąd z fragmentem kodu w pytaniu - zauważ niespójność między porównaniami zastosowanymi dla warn_leveli critical_level. Porównania dla warn_levelsą poprawne, ale critical_levelwykorzystuje -le(mniejsze lub równe) zamiast -lt(tylko mniejsze). Zastanów się, kiedy resultjest nieco większy niż critical_level- zostanie zaokrąglony w dół critical_leveli nie wywoła krytycznego ostrzeżenia, nawet jeśli powinien (i zrobiłby to, gdyby zastosowano -ltporównanie).

Być może nie stanowi to większego problemu, ale oto poprawiony kod:

if [ "$result" -lt "$warn_level" ]; then
  echo "Memory OK. $result% used."
  exit 0;
elif [ "$result" -lt "$critical_level" ]; then
  echo "Memory WARNING. $result% used."
  exit 1;
else
  echo "Memory CRITICAL. $result% used."
  exit 2;
fi

Te -getesty są także zbędne, ponieważ te przypadki są regulowane przy osiągnięciu elif/ else, więc zostały usunięte.

Graeme
źródło
2
Aby jednak sprawdzić wartości progowe, nie chcesz zaokrąglać w górę . 49,6 powinno nadal być OK, jeśli próg ostrzegawczy wynosi 50. Więc result=$(( 100 * $used / $total ))powinno być dobrze.
Stéphane Chazelas
0

Więc nie wiem, jak awkbardzo dobrze korzystać. Wiem jednak, że to, co dzieje się w skrypcie, który podłączyłeś, to dużo bzdur i że coś takiego jak poniżej powinno działać. Przepraszam, że nie mogę napisać tego idealnie, ale skoro już dzwonisz awk- wydaje się, że dwa razy - powinieneś używać czegoś takiego.

_chkmem() { return $( 
    free -m | grep "buffers/cache"
        awk '{ 
        percent = ( $3 / ( $3 + $4 ) ) * 100     
        warn = '"${warnlevel?No warning level specified!}"' < percent ? WARNING : OK
        crit = '"${critical?No critical level specified!}"' < percent ? CRITICAL : $warn
        print "Mem $crit : $percent% used"
        if ( $crit != OK ) exit 1
    }')
}

_chkmem || exit 1
mikeserv
źródło