При написании сценария на bash, иногда может понадобиться быстро подсчитать числа. Например, преобразовать единицы данных, округлить делимое значение до ближайшего целого числа, увеличить счетчик в простых циклах и т. д. Каждый язык программирования имеет встроенную поддержку основных арифметических операций над распространенными типами данных. Однако, поскольку bash не является языком программирования общего назначения, а скорее интерпретатором командной строки, он поставляется с ограниченной поддержкой арифметических операций.
Ограничение Bash для арифметических операций
Переменные в bash не являются строго типизированными. По умолчанию все переменные bash являются символьными строками, если они не указаны с помощью declare. Для поддержки арифметических операций над такими строковыми переменными, bash рассматривает переменные как целые числа, если это определено контекстом выполнения. Операторы арифметики/сравнения к переменным, содержащим только цифры, bash автоматически рассматривает переменные как целые числа. Такое автоматическое преобразование строк в целые числа позволяет bash оценивать целочисленную арифметику. Однако bash не поддерживает вычисления с плавающей запятой нативно, и придется полагаться на внешние инструменты, такие как GNU bc, для операций с плавающей запятой.
Арифметические операции в Bash
Существует множество способов выполнения арифметических операций в bash, для переносимости сценария рекомендуется использовать встроенный механизм bash, а не полагаться на внешние команды. Если вы необходимо выполнить целочисленную арифметику, это окружить арифметическое выражение двойными круглыми скобками, как показано ниже. Формат арифметического выражения, заключенного в круглые скобки, основан на языке программирования C.
1 | (( арифметические-операции )) |
Несколько примеров
1 2 3 4 5 6 7 8 9 10 11 12 | # Целочисленные переменные могут храниться с кавычками или без них a=100 b="3" (( sum = a + b )) # сложение (( sub = a - b )) # вычитание (( mul = a * b )) # умножение (( div = a / b )) # деление (( mod = a % b )) # модуль (остаток) (( exp = a ** b )) # экпонента echo "sum: $sum, sub: $sub, mul: $mul, div: $div, mod: $mod, exp: $exp" |
Результат выполнения операций
1 | sum: 103, sub: 97, mul: 300, div: 33, mod: 1, exp: 1000000 |
Поскольку bash не поддерживает тип данных с плавающей точкой, деление двух переменных всегда будет давать целочисленный результат путем усечения до нуля.
При выполнение арифметических операций, Bash позволяет увеличивать или уменьшать целочисленные переменные.
1 2 3 4 5 | a=100 (( a++ )) echo "a = $a" (( a-= 10 )) echo "a = $a" |
Результат
1 2 | a = 101 a = 91 |
При использовании чисел с плавающей запятой, bash вернет ошибку "syntax error: invalid arithmetic operator".
Присваивание результата арифметической операции переменной
Для присвоение значения переменной используется следующая конструкция
1 | $(( арифметические-операции )) |
Пример
1 2 3 4 5 | a=100 b="3" sum=$(( a + b )) sub=$(( a - b )) |
Использование команды let
Встроенная команда let позволяет вычислять "вложенное" арифметическое выражение.
1 2 3 4 5 6 7 | a=100 b="3" let sum=a+b # перед и после присваивания не должно быть пробела let sub=a-b let mod=a%b let mod=a%b |
Также возможно выполнять несколько арифметических операций в одном операторе let.
1 2 | let 'tmp=a' 'a=b+1' 'b=tmp+1' let 'tmp=a, a=b+1, b=tmp+1' |
Использование команды expr
В отличие от let, которая является встроенной командой bash, expr - это внешняя утилита командной строки. Поскольку она является частью GNU Coreutils, использование expr в сценарии не влияет на переносимость сценария.
1 2 3 4 5 6 7 8 9 | a=100 b="3" # перед и после операторов должны быть пробелы sum=`expr $a + $b` sub=`expr $a - $b` mul=`expr $a \* $b` div=`expr $a / $b` mod=`expr $a % $b` |
Арифметические операции, поддерживаемые expr, - это сложение (+), вычитание (-), умножение (*), деление (/) и модуляция (%). Оператор умножения должен быть экранирован символом '\', так как '*' имеет встроенное значение всех файлов в текущем каталоге.
Использование команды bc (для вычисления с плавающей запятой)
Bash не поддерживает вычисления с плавающей запятой. В случае, если сценарий bash требует вычислений с плавающей заятой, один из способов обойти ограничение bash является использование внешний инструмент. Одним из таких инструментов является GNU bc.
Чтобы передать bc числа с плавающей запятой, необходимо использовать echo.
1 2 3 4 5 6 7 8 9 | a=12.5 b=5.8 # перед и после оператора должны быть пробелы sum=`echo "$a + $b" | bc` mul=`echo "$a * $b" | bc` div=`echo "scale=2; $a / $b"| bc` echo "sum: $sum, mul: $mul, div: $div" |
В bc можно настроить точность чисел с плавающей запятой, изменив переменную scale. Так, например, результат следующего деления с плавающей точкой будет включать две десятичные цифры после запятой.
1 | div=`echo "scale=2; $a / $b" | bc` |
Результат работы сценарий
1 | sum: 18.3, mul: 72.5, div: 2.15 |