Краска числами

Используя математику в сценариях оболочки одна область, часто игнорирующаяся документацией по сценариям оболочки — вероятно, потому что так мало людей фактически понимает предмет. Сценарии оболочки были разработаны больше для основанной на операция со строками обработки с числовым вычислением как что-то вроде запоздалой мысли, таким образом, это не должно удивлять.

Эта глава в основном касается основных целочисленных математических операций в сценариях оболочки. Более сложная математика в основном вне возможности оболочки, пишущей сценарий в целом, хотя можно сделать такую математику с помощью встроенных сценариев Perl или путем выполнения bc команда. Эти два метода описаны во Вне Основной Математики.

expr Команда Также Делает Математику

В сценариях оболочки числовые вычисления сделаны с помощью команды expr. Эта команда берет серию параметров, каждый из которых должен содержать единственный маркер от выражения, которое будет оценено. Каждое число или символ должно таким образом быть отдельным параметром.

Например, выражение (3*4)+2 записан как:

expr '(' '3' '*' '4' ')' '+' '2'

Команда распечатает результат (14) к его стандартному выводу,

Для числовых сравнений используется тот же базовый синтаксис. Протестировать истину неравенства 3 < -2, используйте следующее утверждение:

expr '3' '<' '-2'

Это возвратит нуль (0) потому что оператор не является истиной. Если бы это была истина, то это возвратило бы один (1).

Наиболее распространенное место для использования этой команды как часть цикла в сценарии оболочки. То, что следует, является простым примером для-следующего цикл, записанный в сценарии оболочки:

COUNT=0
while [ $COUNT -lt '4' ] ; do
    echo "COUNT IS $COUNT"
    COUNT="$(expr "$COUNT" '+' '1')"
done

Этот сценарий эквивалентен следующему биту C:

int i;
for (i=0; i<4; i++) {
    printf("COUNT IS %d\n", i);
}

Простой способ: круглые скобки

Другой способ выполнить в математических операциях some Диалекты оболочки Bourne с двойными встроенными круглыми скобками. Пример ниже иллюстрирует этот метод:

echo $((3 + 4))

Эту форму намного проще использовать, чем expr команда, потому что это несколько менее строго с точки зрения форматирования. В частности за исключением переменного декодирования, отключено расширение оболочки. Таким образом операторы как меньше, чем и больше, чем не должны быть заключены в кавычки.

Эта форма не без ее проблем, как бы то ни было. В частности это не так широко совместимо как использование expr. Эта форма является расширением, добавленным оболочкой Korn (ksh), и позже принятый оболочкой Z (zsh) и Граница Снова окружает (bash). В чистой среде Оболочки Bourne вероятно перестанет работать этот синтаксис.

В то время как самые современные основанные на UNIX и подобные UNIX операционные системы используют BASH для эмуляции Оболочки Bourne, при попытке записать сценарии, которые более широко применимы, необходимо использовать expr чтобы сделать целочисленная математика, как описано в expr Команде Также Делает Математику.

Частые ошибки

Как упомянуто в, Основы Сценария оболочки, язык сценариев оболочки содержит основное тестирование равенства без использования expr команда. Например:

if [ 1 = 2 ] ; then
    echo "equal"
else
    echo "not equal"
fi

Этот код будет работать как ожидалось. Однако это не делает то, что Вы могли бы первоначально думать, что это делает; это выполняет сравнение строк, не числовое сравнение. Таким образом следующий код не будет вести себя способ, которым Вы могли бы ожидать, приняли ли Вы числовое сравнение:

if [ 1 = "01" ] ; then
    echo "equal"
else
    echo "not equal"
fi

Это распечатает слова, «не равные», поскольку строки «1» и «01» не являются той же строкой.

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

Следующий код демонстрирует это в действии:

expr '1' '+' '2'
expr ' 1' '+' '2'
expr '2' '<' '1'
expr ' 2' '<' '1'

Первая строка распечатает число 3. Вторая строка производит сообщение об ошибке. При выполнении дополнения эту ошибку просто обнаружить. При выполнении сравнений, однако, как показано в следующих двух строках, результаты более коварны. Число 2 ясно больше, чем число 1. В сравнении строк, однако, пространство виды перед любой буквой или числом. Таким образом третья строка распечатывает a 0, в то время как четвертая строка распечатывает a 1. Это, вероятно, не, что Вы хотите.

Как с большинством вещей в сценариях оболочки, существует много способов решить эту проблему, в зависимости от Ваших потребностей. Если Вы только волнуетесь по поводу пробелов, и если цель для сравнения состоит в том, чтобы управлять выполнением оболочки, можно использовать числовые подпрограммы оценки, созданные в test, как описано в test страница справочника.

Например:

MYNUMBER=" 2" # Note this is a string, not a number.
# Force an integer comparison.
if [ "$MYNUMBER" -gt '1' ] ; then
    echo 'greater'
fi

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

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

MYRAWNUMBER=" 2" # Note this is a string, not a number.
 
# Strip off any characters that aren't in the range of 0-9
MYNUMBER="$(echo "$MYRAWNUMBER" | sed 's/[^0-9]//g')"
 
expr "$MYNUMBER" '<' '1'

Это приводит к сравнению между числом 2 и число 1, как ожидалось.

Для получения дополнительной информации о регулярных выражениях посмотрите Освобожденные Регулярные выражения.

Вне основной математики

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

Существует два основных способа сделать математические операции с плавающей точкой (и другой, более сложная математика). Первое с помощью встроенного кода Perl, второе с помощью bc команда. Этот раздел представляет обе формы кратко.

Математические операции с плавающей точкой Используя встроенный Perl

Первый метод выполнения математических операций с плавающей точкой оболочки, встроенного Perl, является самым простым схватить. Для использования этого метода Вы по существу пишете короткий сценарий Perl, затем заменяете переменными оболочки в сценарий, затем передаете его perl интерпретатор, или путем записи его в файл или путем передачи его в как параметр командной строки.

Следующий пример демонстрирует основные математические операции с плавающей точкой с помощью встроенного Perl. Это принимает основное понимание языка программирования Perl.

#!/bin/sh
PI=3.141592654
RAD=7
AREA=$(perl -e "print \"The value is \".($PI * ($RAD*$RAD)).\"\n\";")
echo $AREA

При нормальных обстоятельствах Вы, вероятно, не хотите распечатывать всю строку при выполнении этого. Однако использование строки должно было продемонстрировать важный момент. Perl оценивает строки между метками одинарной и двойной кавычки по-другому, поэтому при выполнении встроенного Perl, часто необходимо использовать двойные кавычки. Однако оболочка только оценивает переменные оболочки в двойных кавычках. Таким образом метки двойной кавычки в сценарии должны быть заключены в кавычки так, чтобы они фактически были переданы интерпретатору Perl вместо того, чтобы закончить или начать новые параметры командной строки.

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

Математические операции с плавающей точкой Используя до н.э Команду

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

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

Вот пример использования bc в сценарии оболочки:

#!/bin/sh
 
PI=3.141592654
RAD=7
AREA=$(echo "$PI * ($RAD ^ 2)" | bc)
echo "The area is $AREA"

bc команда предлагает намного больше функциональности, чем описанный в этом разделе. Этот раздел только предназначается как краткое резюме доступной функциональности. Для полных примечаний использования см. страницу справочника для bc.