Linux: работа с числами (bc, dc, expr)

http://www.basicallytech.com/blog/?/archives/23-command-line-calculations-using-bc.html  – примеры расчета простых выражений с помощью bc.

expr и let – базовые целочисленные калькуляторы. Поддерживают операции сложения/деления/умножения/вычитания.

EXPR
$ expr 6 + 2
8

$ expr 6 - 2
4

$ expr 6 \* 2
12

$ expr 6 / 2
3

$ expr 6 / 5
1

LET
let "b = $a * 2"
let "b = $a - 2"

bc (basic calculator) — интерактивный интерпретатор Си-подобного языка, позволяет выполнять вычисления с произвольно заданной точностью. Часто используется как калькулятор в командной строке UNIX-подобных операционных систем.

echo '57+43' | bc # addition
echo '57-43' | bc # subtraction
echo '57*43' | bc # multiplication

bc bash float / scale – работает, только 0 теряется 🙂

# echo "scale=2; 4/10" | bc
.40
# echo "scale=2; 4/5" | bc
.80
# echo "scale=2; 4/4" | bc
1.00
# echo "scale=4; 271/1070" | bc
.2532
# echo "scale=4; 147/1070" | bc
.1373

Калькуляция в bash без expr и bc – через переменные bash, echo и AWK. Другие вариации описаны тут.

runtime=$((end-start))
echo $((a=22,b=333,c=b/a,c))
awk "BEGIN {print 22/7}"

Good Solution is to get Nearest Round Number is – очень красивое решение с + 0.5 🙂

ram_available_perc=$(awk "BEGIN {print ($ram_available/$ram_total)*100}")
ram_available_rounded=$(echo $ram_available_perc | awk '{print int($1+0.5)}')

HEX/DEC/BIN CONVERSION (преобразование между системами счисления)

Можно использовать bc для конвертации между системами.
 
Между двоичной и десятичной.
> echo "ibase=2\n111"|bc
7

> echo "obase=2\n7"|bc
111
Между десятичной и шестнадцетиричной.
> echo 255 |dc -e "16o?p"
FF
> echo "ibase=16; FF" | bc
255

К примеру скрипт, который который конвертирует из десятичной в 16-тиричную полное число, потом разделяет шестнадцатиричные числа на две группы (одна с двумя символами – одним байтом, а вторая с четырьмя – двумя байтами) и конвертит группы раздельно обратно в шестнадцатиричную систему. Конвертация из десятичной в шестнадцатиричную делается через dc, обратно – через bc.

#!/usr/local/bin/bash

DEC=$1
HEX=$(echo $DEC |dc -e "16o?p")
HEX_SEPARATED_1=$(echo $HEX | sed 's/^\(.\{2\}\)/\1 /' | awk '{print $1}')
HEX_SEPARATED_2=$(echo $HEX | sed 's/^\(.\{2\}\)/\1 /' | awk '{print $2}')
DEC_SEPARATED_1=$(echo "ibase=16; $HEX_SEPARATED_1" | bc)
DEC_SEPARATED_2=$(echo "ibase=16; $HEX_SEPARATED_2" | bc)
echo "$DEC = $HEX = $DEC_SEPARATED_1/$DEC_SEPARATED_2"

IF numbers (float compare)

IF встроенный в bash умеет работать только с целыми числами. Для обхода этого ограничения следует использовать bc. К примеру, если нам нужно сравнить два числа с запятой, мы их сравниваем посредством bc, который выдает результат 1/0, а далее, посредством IF = 1 мы делаем то или иной действие. Использовал данную фичу в скрипте для сравнения полученного значения TX/RP-Power с эталонным.

Bash does not understand floating point arithmetic. It treats numbers containing a decimal point as strings.
$ echo "1.2 > 1.1" | bc
1

$ echo "1.2 > 1.3" | bc
0

COMPARE_RESULT_THROUGH_BC=$(echo "$TX_Power_mW > $TX_POWER_HIGH" | bc)
if [[ $COMPARE_RESULT_THROUGH_BC -eq 1 ]]; then
:some_code:
fi

Leave a Reply