Показаны сообщения с ярлыком bash. Показать все сообщения
Показаны сообщения с ярлыком bash. Показать все сообщения

среда, 23 февраля 2011 г.

Сравнение вещественных чисел в bash

Я продолжаю писать инструмент для слежения за самодельным вэб-сервером.
Сегодня наткнулся на новую особенность bash — он не умеет работать с вещественными числами (с плавующей точкой). Например он не может их сравнивать:
if [ 0.1 -gt 0.3 ]

возвращает ошибку «bin/run.bash: строка 44: [: 0.1: ожидается числовое выражение».
Пользователь MoneyCat пишет что лучше для этого использовать операторы <, >, <=, >=:
if [ 0.1 > 0.3 ]

Ошибка хоть и перестала появляться, но зато скрипт начал просто неверно работать.
Как нам дружелюбно напоминает Advanced Bash-Scripting Guide:
Bash does not understand floating point arithmetic. It treats numbers containing a decimal point as strings.
Чтобы обойти это ограничение можно воспользоваться bc:
if [ $(echo "$max < $i" | bc) -eq 1 ]


Теперь мой скрипт так же умеет следить и за загрузкой процессора. Он получает % от используемого моей программой процессорного времени в виде вещественного числа от команды ps:
CPUUSE=$(ps h -p $TARG_PID -o pcpu)

Слежение за процессом из bash скрипта

Я решил поднять у себя на машине самодельный веб-сервер. Естественно хочется чтобы он не мешал во время работы, а так как сервер самодельный риск всяких утечек памяти и зацикливаний высок — нужно средство слежения которое в критический момент будет убивать мою поделку.
В качестве языка я выбрал bash, т.к. программы на нём жрут очень мало ресурсов.

Пока делал эту прогу, мне показались интересными три момента:
  1. Отлавливание сигналов происходит при помощи команды trap
    trap "echo Hello world" SIGHUP SIGINT SIGTERM
  2. Самым надёжным способом выяснить в какой папке лежит сам скрипт является команда lsof
    LSOF=$(lsof -p $$ | grep -E "/"$(basename $0)"$")
    MY_PATH=$(echo $LSOF\
    | sed -r s/'^([^\/]+)\/'/'\/'/1 2>/dev/null)
    MY_ROOT=$(dirname $MY_PATH)
  3. Судя по всему самый надёжный способ узнать сколько памяти занимает процесс — это сложить значения RSS и Dirty команды pmap
    MEMUSE_RAW=$(pmap -x $TARG_PID 2>/dev/null | grep total\
    | sed 's/-//g' | sed s/[^0-9\ ]*//g);
    RSS=$(echo $MEMUSE_RAW | awk '{print $2}')
    DIRTY=$(echo $MEMUSE_RAW | awk '{print $3}')
    MEMUSE=$(echo $RSS+$DIRTY | bc)
Весь код скрипта: