Я использовал несколько способов сделать некоторую простую целочисленную арифметику в Bash (3.2). Но я не могу выяснить лучший (предпочтительный) способ сделать это.
result=`expr 1 + 2`
result=$(( 1 + 2 ))
let "result = 1 + 2"
Каковы принципиальные различия между теми выражениями?
Там другие пути состоят в том, чтобы сделать то же?
Использование инструмента как bc
обязательный для арифметики с плавающей точкой?
result=`echo "7/354" | bc`
В 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
Изменить:
Конструкция $ (())
называется " арифметическим расширением "и приводит к тому, что содержимое оценивается как целочисленное выражение. Это элемент синтаксиса оболочки.
Если переменная объявлена как целое число, вам не нужно использовать какую-либо форму двойных скобок, вы можете опустите знак доллара в имени переменной (как в формах с двойными круглыми скобками), но вы не можете добавлять пробелы вокруг операторов:
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
включает порождение ex внутренний исполняемый файл, который может быть довольно дорогим для большого количества вычислений в цикле.Его следует использовать только - в средах, где оболочка не может выполнять свои собственные арифметические операции, или для переносимости, когда сценарий может найти свой путь в такой среде. Оболочки POSIX имеют арифметические возможности, поэтому это будет проблемой только в старых системах.
Что касается использования bc
для арифметики с плавающей запятой, это или что-то подобное требуется при использовании Bash и многих других оболочек. POSIX говорит, что «требуется только длинная целочисленная арифметика со знаком».
Две оболочки, которые действительно поддерживают математику с плавающей запятой, - это ksh и zsh. Помимо bc
, вы можете использовать dc
, AWK, Python, Perl и другие из сценария Bash.
Одна вещь, которую Bash будет делать с числами с плавающей запятой, - это печатать их с помощью встроенной функции printf
(обратите внимание, что есть также внешний printf
, но встроенный имеют приоритет).
printf "%'14.4f\n" 1234.56 # result " 1,234.5600" (in my locale)
Третий вариант, который у вас есть, гораздо менее читабелен, поскольку он не похож на оператор присваивания. Первый, как отметили другие, вызывает внешнюю команду
Я предпочитаю второй вариант, так как для него не нужна внешняя утилита:
result=$(( 1 + 2 ))
Первый вариант вызывает expr
для вычисления - я не знаком с let
. Другой альтернативой bc
является dc
. Выбери свой фаворит.
Я не могу сказать, что это "обязательно", но bc
, вероятно, лучше всего подходит для арифметики общего назначения.
Для чего-то более интересного вы всегда можете использовать Perl.
Обратной стороной обоих подходов является то, что они оба открывают дочерний процесс, поэтому выполнение этого в замкнутом цикле будет медленнее, чем собственные выражения bash (такая же проблема возникает при использовании обратных кавычек в вашем первом примере). Я не уверен, вызывает ли $ (())
дочерний процесс.
Обязательно ли использование такого инструмента, как bc, для арифметики с плавающей запятой?
Нет, если вы используете оболочку, которая поддерживает операции с плавающей запятой, например zsh , кш. В противном случае, если вы хотите выполнять более сложные математические операции с плавающей запятой, используйте один из них, bc / awk / dc
. Конечно, Perl / Python и т. Д. Тоже.