Выражения и арифметика в bash
Bash поддерживает ТОЛЬКО целочисленные выражения. Если нужно выполнить float выражения, можно использовать сторонние утилиты. Как один из вариантов, сделать скрипт fp
с таким содержанием:
#!/usr/bin/env bash
# fp - реализация операций с плавающей точкой через awk
# usage: fp "выражение"
awk "BEGIN { print $* }"
Арифметика в двойных круглых скобках (( ))
В двойных круглых скобках (())
выполняются арифметические вычисления. Внутри (())
не требуются $
перед именами переменных. Их можно встретить в цикле for или в if:
for ((i=0; i<size; i++)); do :; done
if (( max - 3 > x * 4 )); then :; fi
Результат выражения можно присвоить переменной, добавив $
:
max=$(( intro + body + outro - 1 ))
median_loc=$((len / 2))
В операторе if $
не нужен, т.к. там для принятия решения достаточно булевых значений. Если при вычислении выражения в двойных круглых скобках (без $
) получается ненулевой результат --> возвращается статус 0
(true
), иначе - статус 1
(false
).
(())
без $
интерпретируются как выполнение одной/нескольких команд, которые не возвращают результат вычислений. Хоть и есть исключения:
# Bash поддерживает некоторые C-like операторы присваивания
(( step ++ ))
(( median_loc = len / 2 ))
(( dist *= 4 ))
Выражения выше всё равно не возвращают ничего (кроме кода возврата в \$?), а только присваивают значение переменным. Их можно оформить и так:
step=$(( step ++ ))
median_loc=$(( median_loc = len / 2 ))
dist=$(( dist *= 4 ))
Не юзай $((step++)) как самостоятельную инструкцию в отдельной строке
Такие выражения опасно юзать как самостоятельные инструкции, ибо они будут возвращать числа (из-за $
), которые интерпретатор воспримет как имя какой-то команды: если, например, выражение вернет 3 --> оболочка попытается запустить команду с именем 3.
![[Переменные в bash#^e5ea05]]
Однако внутри круглых скобок пробелы допускаются, ибо круглые скобки определяют границы этого "слова".
Пару слов о let
Раньше вместо (())
использовали (и используют) встроенную команду let
:
# Эквивалентные выражения
(( step ++ ))
let "step++"
(( median_loc = len / 2 ))
let "median_loc = len / 2"
(( dist *= 4 ))
let "median_loc = len / 2"
Выражение let
бери в кавычки
let
принимает только одно "слово", а пробелы в выражении разделяют выражение на несколько слов (чревато синтаксической ошибкой), и чтобы не было ошибок --> арифметическое выражение заключай в кавычки.
"Голая" арифметика
Есть один не очень желательный способ выполнения арифметических вычислений без использования (())
или let
--> суть в объявлении заранее переменной как integer, после которого можно будет с переменной выполнять арифметические вычисления без (())
или let
:
declare -i SEE
X=9
Y=3
SEE=X+Y # 12 (интерпретируется как АРИФМЕТИЧЕСКАЯ операция)
SAW=X+Y # X+Y (интерпретируется как СТРОКОВЫЙ литерал)
SUU=$X+$Y # 9+3 (интерпретируется как КОНКАТЕНАЦИЯ строк)
Такой стиль выполнения арифметических действий чреват ошибками, ибо:
1) Можно просто забыть объявить переменную как целочисленную
2) Оболочка не сообщит об "ошибке"
3) Не очень очевидно в коде будет, какая из переменных integer
Соус: Книга "Идиомы Bash" --> Глава 5. "Выражения и арифметика"