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

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

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

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

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

result=`echo "7/354" | bc`
19
задан jww 29 September 2019 в 20:50
поделиться

5 ответов

В 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)
18
ответ дан 30 November 2019 в 04:07
поделиться

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

0
ответ дан 30 November 2019 в 04:07
поделиться

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

result=$(( 1 + 2 ))

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

5
ответ дан 30 November 2019 в 04:07
поделиться

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

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

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

4
ответ дан 30 November 2019 в 04:07
поделиться

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

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

3
ответ дан 30 November 2019 в 04:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: