Ошибка сценария Bash: ожидается целочисленное выражение

13

У меня довольно странная проблема, я запускаю скрипт (Bash) на нескольких серверах, и он перестал работать на одном из серверов (прекрасно работает на всех других серверах).

Вот проблемная часть сценария: (я сам не написал, все кредиты идут в «Rich») ( http://www.notrainers.org/monitoring-memory-usage-on-linux-with-nagios- and-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

Полное сообщение об ошибке:

./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

Если вам нужна дополнительная информация, дайте мне знать, и я постараюсь предоставить ее как можно быстрее.

Цените все материалы :)

Adalsteinn
источник

Ответы:

5

По предоставленной вами ссылке я вижу строку ниже.

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

Согласно комментарию @ Graeme, измените вышеприведенную строку на нижнюю.

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

Теперь, после добавления строки выше, мы должны изменить вывод resultцелого числа, как показано ниже.

result1=${result/.*}

Я предполагаю, что на одной из машин, где возникает ошибка, этот вывод не является целым числом. Просто преобразуйте результат результата в целое число, чтобы вы могли обрабатывать такие случаи. Добавьте строку ниже после расчета result.

result1=${result/.*}

И вместо resultизменения имен переменных, как result1внутри ifциклов, и ошибки не возникнет.

Я подозреваю, что cut -c -2атрибуты ошибки в основном потому, что она обрезает только первые 2 символа. Что если результат имеет только один символ? Предположим, что в случае результата 1.23456вышеприведенное сокращение приведет 1.к значению, resultкоторое, очевидно, является причиной integer expectedошибки.

Причина, по которой он работает нормально на остальных серверах, заключается в том, что он не сталкивался со случаем, когда resultпеременная имеет только одну цифру. Очень вероятно, что и на остальных серверах произойдет сбой, если результатом будет однозначная переменная (что-то вроде того, что я упоминал в приведенном выше примере).

Рамеш
источник
${result%%.*}будет правильным расширением, чтобы удалить десятичную точку здесь. Но обратите внимание, что это cut -c -2также вызовет проблемы с числами от 100 и более, поэтому безопаснее полностью его отбросить.
Грэм
@ Грэм, я пропустил это. Я должен был внести изменения в этой строке :)
Рамеш
6

Судя по всему, ваша resultпеременная содержит число .после того, как число, заставляющее bash не распознавать его как таковое. Вы можете воспроизвести ошибку, просто выполнив:

[ 7. -gt 1 ]

Если вы добавите больше сценария к своему вопросу, я могу предложить, откуда это может исходить.

Обновить

Глядя на полный скрипт, я бы просто заменил строку:

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

С:

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

Так как usedи totalявляются целыми числами и bashвыполняет целочисленную арифметику, хотя обратите внимание, что смещение умножения будет 100 к началу. Или, если вы хотите обеспечить правильное округление («целочисленное деление» в вычислениях всегда эффективно округляет):

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

Это гарантирует, что в нем нет конечных точек result. Использование подхода cutне очень хорошая идея, так как оно действительно только для результата в диапазоне 10-99. Это не удастся для result0-9 (как в вашем случае), а также чисел выше 99.

Обновление 2

Из комментария @ Stephane ниже , вам лучше округлять при сравнении с пороговыми значениями. Учитывая это, есть еще одна небольшая ошибка с фрагментом в вопросе - обратите внимание на несоответствие между сравнениями, используемыми для warn_levelи critical_level. Сравнения для warn_levelявляются правильными, но critical_levelиспользуют -le(меньше или равно) вместо -lt(просто меньше). Подумайте, когда resultоно немного больше, чем critical_level- оно будет округлено до critical_levelи не вызовет критического предупреждения, даже если оно должно (и будет при -ltсравнении).

Возможно, не большая проблема, но вот исправленный код:

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

Эти -geтесты также излишним , поскольку эти случаи имеются в виду при достижении elif/ else, поэтому были удалены.

Graeme
источник
2
Однако, чтобы проверить против порогов, вы не хотите , чтобы округлить до . 49.6 все равно должно быть в порядке, если порог предупреждения равен 50. Так что result=$(( 100 * $used / $total ))должно быть в порядке.
Стефан Шазелас
0

Так что я не знаю, как использовать awkочень хорошо. Но я знаю, что в сценарии, который вы связали, происходит много глупостей, и что-то вроде следующего должно работать. Извините, я не могу написать это на отлично, но так как вы уже звоните awk- кажется, дважды - вам следует использовать что-то подобное.

_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
источник