параметр++
Постинкремент переменной. Эквивалентно выражению параметр = параметр + 1. (Но см. обсуждение ниже.)
параметр--
Постдекремент переменной. Эквивалентно выражению параметр = параметр - 1
++параметр
Преинкремент переменной. Эквивалентно выражению параметр = параметр + 1
--параметр
Предекремент переменной. Эквивалентно выражению параметр = параметр - 1
Эти операторы присваивания обеспечивают удобный и компактный способ записи многих арифметических вычислений. Особый интерес представляют операторы инкремента (++) и декремента (--), они увеличивают или уменьшают значение своего параметра на 1. Эти операторы заимствованы из языка программирования C и внедрены в несколько других языков программирования, включая bash.
Операторы инкремента и декремента могут находиться перед параметром или после него. Хотя в обоих случаях они увеличивают или уменьшают значение параметра на 1, тем не менее их местоположение играет важную роль. Если оператор помещается перед параметром, сначала выполняется операция инкремента (или декремента) и только потом возвращается измененное значение параметра. Если оператор помещается за параметром, операция выполняется после возврата значения. Такое поведение может показаться странным, но оно реализовано с умыслом. Взгляните на следующий пример:
[[email protected] ~]$ foo=1
[[email protected] ~]$ echo $((foo++))
1
[[email protected] ~]$ echo $foo
2
Если присвоить переменной foo значение 1 и затем увеличить ее значение с помощью оператора ++, следующего за именем переменной, выражение вернет прежнее значение 1 переменной foo. Однако если вывести значение переменной второй раз, мы увидим увеличенное значение. Если поместить оператор ++ перед параметром, мы получим более ожидаемый результат:
[[email protected] ~]$ foo=1
[[email protected] ~]$ echo $((++foo))
2
[[email protected] ~]$ echo $foo
2
Для большинства приложений на языке командной оболочки более полезным будет префиксный оператор.
Операторы ++ и -- часто используются совместно с циклами. Внесем некоторые улучшения в сценарий, демонстрирующий применение оператора деления по модулю, чтобы немного сократить его:
#!/bin/bash
# modulo2 : демонстрация оператора деления по модулю
for ((i = 0; i <= 20; ++i )); do
if (((i % 5) == 0 )); then
printf "<%d> " $i
else
printf "%d " $i
fi
done
printf "n"
Битовые операции
Командной оболочкой поддерживается класс операторов, которые манипулируют числами не совсем обычным способом. Эти операторы действуют на уровне битов. Они применяются для выполнения некоторых низкоуровневых операций, часто связанных с установкой или чтением битовых флагов. Описание битовых операторов приводится в табл. 34.4.
Таблица 34.4. Битовые операторы
Оператор
Описание
~
Поразрядное отрицание. Изменяет значения всех битов в числе на противоположные
<<
Поразрядный сдвиг влево. Сдвигает все биты в числе на один разряд влево
>>
Поразрядный сдвиг вправо. Сдвигает все биты в числе на один разряд вправо
&
Поразрядная операция И (AND). Выполняет операцию И над всеми битами двух чисел
|
Поразрядная операция ИЛИ (OR). Выполняет операцию ИЛИ над всеми битами двух чисел
^
Поразрядная операция ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR). Выполняет операцию ИСКЛЮЧАЮЩЕЕ ИЛИ над всеми битами двух чисел
Обратите внимание, что для всех битовых операторов, кроме поразрядного отрицания, существуют соответствующие операторы присваивания (например, <<=).
Ниже показано, как с использованием оператора поразрядного сдвига влево вывести список степеней 2:
[[email protected] ~]$ for ((i=0;i<8;++i)); do echo $((1<<i)); done
1
2
4
8
16
32
64
128
Логические операторы
Как мы узнали в главе 27, составная команда (( )) поддерживает разные операторы сравнения. Однако существует еще несколько операторов, которые можно использовать для оценки. Полный список приводится в табл. 34.5.
Таблица 34.5. Операторы сравнения
Оператор
Описание
<=
Меньше или равно
>=
Больше или равно
<
Меньше
>
Больше
==
Равно
!=
Не равно
&&
Логическое И (AND)
||
Логическое ИЛИ (OR)
выражение1?выражение2:выражение3
Тернарный (трехместный) оператор сравнения. Если выражение1 вернет ненулевое значение (арифметическую истину), будет выполнено выражение2, иначе — выражение3
При использовании логических операторов в арифметических выражениях действуют следующие правила: выражение, возвращающее 0, считается ложным, а выражение, возвращающее ненулевое значение, — истинным. Составная команда (( )) отображает результаты в обычные для командной оболочки коды завершения:
[[email protected] ~]$ if ((1)); then echo "true"; else echo "false"; fi
true
[[email protected] ~]$ if ((0)); then echo "true"; else echo "false"; fi
false
Самым странным из логических операторов выглядит тернарный (или трехместный) оператор. Этот оператор (заимствованный из языка программирования C) самостоятельно выполняет логическую проверку. Его можно использовать вместо инструкции if/then/else. Он оперирует тремя арифметическими выражениями (этот оператор не работает со строками), и если первое выражение оценивается как истинное (то есть возвращает ненулевое значение), выполняется второе выражение. Иначе выполняется третье выражение. Опробуем его в командной строке.
[[email protected] ~]$ a=0
[[email protected] ~]$ ((a<1?++a:--a))
[[email protected] ~]$ echo $a
1
[[email protected] ~]$ ((a<1?++a:--a))
[[email protected] ~]$ echo $a
0
Этот пример реализует переключение значения переменной. Каждый раз, когда выполняется оператор, значение переменной a переключается с 0 на 1 или обратно.
Обратите внимание, что прямое присваивание в этом операторе считается недопустимой операцией. Если попытаться выполнить присваивание, bash сообщит об ошибке:
[[email protected] ~]$ a=0
[[email protected] ~]$ ((a<1?a+=1:a-=1))
bash: ((: a<1?a+=1:a-=1: attempted assignment to non-variable (error token is "-=1")
Эту проблему можно решить, заключив выражения присваивания в круглые скобки:
[[email protected] ~]$ ((a<1?(a+=1):(a-=1)))
Далее приводится более полный пример использования арифметических операторов в сценарии, который выводит простую таблицу чисел:
#!/bin/bash
# arith-loop: сценарий для демонстрации арифметических операторов
finished=0
a=0
printf "ata**2ta**3n"
printf "=t====t====n"
until ((finished)); do
b=$((a**2))
c=$((a**3))
printf "%dt%dt%dn" $a $b $c
((a<10?++a:(finished=1)))
done
В этом сценарии мы реализовали цикл until, проверяющий значение переменной finished. Первоначально переменной присвоено значение 0 (арифметическая ложь). Цикл продолжается, пока эта переменная не получит ненулевое значение. Внутри цикла вычисляются квадрат и куб переменной-счетчика a. В конце цикла выполняется проверка значения этой переменной. Если оно меньше 10 (максимальное число итераций), она увеличивается на 1, иначе переменной finished присваивается значение 1, что превращает ее в арифметическую истину, и цикл завершается. Запустив сценарий, вы получите следующий результат:
[[email protected] ~]$ arith-loop
a a**2 a**3
= ==== ====
0 0 0
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
bc — язык калькулятора для вычислений с произвольной точностью
Мы уже знаем, что командная оболочка поддерживает все виды арифметических вычислений с целыми числами, но как быть, если понадобится реализовать какие-нибудь вычисления из высшей математики или хотя бы просто задействовать вещественные числа? Ответ: никак. По крайней мере, средствами командной оболочки. Для подобных вычислений придется использовать внешнюю программу. Существует множество вариантов решения этой проблемы. Одно из них — использовать программы на встроенном Perl или AWK, но, к сожалению, описание этих языков выходит далеко за рамки данной книги.
Другое решение — использовать специализированную программу-калькулятор. В большинстве систем Linux имеется одна из таких программ — программа с именем bc.
Программа bc читает файл с исходным кодом на собственном языке, напоминающем язык C, и выполняет его. Сценарий на языке bc можно хранить в отдельном файле или передавать его на стандартный ввод программы. Язык bc поддерживает массу возможностей, включая переменные, циклы и функции, определяемые программистом. Мы не будем рассматривать программу bc во всех подробностях, а познакомимся лишь с некоторыми ее возможностями, чтобы вы могли получить общее представление. Неплохое описание программы bc можно найти на странице справочного руководства (man).