Подтвердить что ты не робот

Арифметические выражения в Bash?

Я использовал несколько способов сделать некоторую простую целочисленную арифметику в BASH (3.2). Но я не могу понять лучший (предпочтительный) способ сделать это.

result=`expr 1 + 2`
result=$(( 1 + 2 ))
let "result = 1 + 2"

Каковы основные различия между этими выражениями?
Есть ли другие способы сделать то же самое?

Является ли использование инструмента вроде bc обязательным для арифметики с плавающей запятой?

result=`echo "7/354" | bc`
4b9b3361

Ответ 1

В Bash, let допускается несколько назначений в строке:

let a=3 b=4 c=5

Как вы видите в своем вопросе, цитирование аргумента let позволяет помещать пробелы вокруг операторов. Однако вы можете опустить кавычки, если избегаете использования пробелов.

Другая форма, использующая двойные круглые скобки в начале инструкции (вместо формы i=$((j + 1))), позволяет включать пробелы вокруг знака равенства или выполнять операции после или приращения или уменьшения и дополнительных присваиваний:

(( a = ( b + c ) * 4 ))
(( count++ ))
(( d = --c**2 ))
(( e *= 2 ))
(( f = 3, g = 5 ))    # multiple operations require a comma separator

Если вы выполняете help "((", это говорит о том, что двойные круглые скобки эквивалентны "let EXPRESSION".

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

blue=2
name=blue
declare $name=4
echo $blue    # result: 4
echo ${!name} # result: 4

Edit:

Конструкция $(()) называется " арифметическое расширение" и заставляет содержимое оцениваться как целочисленное выражение. Это синтаксический элемент оболочки.

Если переменная объявлена ​​как целое число, вам не нужно использовать любую форму двойных скобок, вы можете опустить знак доллара из имени переменной (как в формах с двойными скобками), но вы не можете добавить пространства вокруг операторов:

declare -i x=1   # set integer, initialize to 1
declare +i s=1   # clear integer, initialize to 1
x+=1             # could also be x=x+1
echo $x          # result: 2 (addition)
s+=1             # could also be s=$s+1, requires a "$"
echo $s          # result: 11 (string concatenation)

В отличие от форм выше, вызов expr включает в себя нереста внешнего исполняемого файла, который может быть довольно дорогим для большого количества вычислений в цикле. Единственный раз, когда он должен использоваться, - в средах, где оболочка не может выполнять свою собственную арифметику или переносимость, когда script может найти свой путь в такую ​​среду. У оболочек POSIX есть арифметические возможности, поэтому это будет проблемой только для старых систем.

Что касается использования bc для арифметики с плавающей запятой, то это или что-то подобное требуется при использовании Bash и многих других оболочек. POSIX говорит, что "требуется только подписанная длинная целочисленная арифметика".

Две оболочки, поддерживающие математику float, - ksh и zsh. В дополнение к bc вы можете использовать dc, AWK, Python, Perl и другие из Bash script.

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

printf "%'14.4f\n" 1234.56  # result "    1,234.5600" (in my locale)

Ответ 2

Я предпочитаю ваш второй вариант, так как ему не нужна внешняя утилита:

result=$(( 1 + 2 ))

Первый вариант вызывает expr для выполнения математики - я не знаком с let. Другой альтернативой bc является dc. Выберите свой любимый.

Ответ 3

Я не могу сказать, что это "обязательный", но bc, вероятно, лучший выбор для арифметики общего назначения.

Для чего-то более приятного, вы всегда можете проехать через Perl.

Недостатком обоих подходов является то, что они оба открывают дочерний процесс, поэтому его выполнение в узком цикле будет медленнее, чем родные выражения bash (такая же проблема возникает при использовании обратных шагов в первом примере). Я не уверен, вызывает ли $(()) дочерний процесс.

Ответ 4

Is the use of a tool like bc mandatory for floating point arithmetic?

Нет, если вы используете оболочку, которая поддерживает плавающие точки, например zsh, ksh. В противном случае, если вы хотите выполнить более сложные математические вычисления с плавающей запятой, используйте один из них, bc/awk/dc. Конечно, Perl/Python и т.д. Также.

Ответ 5

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