Присваивание
Хотя на данном этапе это не очевидно, тем не менее арифметические выражения могут выполнять операцию присваивания. Мы уже выполняли присваивание много раз, хотя и в других контекстах. Каждый раз, передавая переменной число, мы выполняем присваивание. То же самое можно делать в арифметических выражениях:
[me@linuxbox ~]$ foo=
[me@linuxbox ~]$ echo $foo
[me@linuxbox ~]$ if (( foo = 5 ));then echo "It is true."; fi
It is true.
[me@linuxbox ~]$ echo $foo
5
В примере выше мы сначала присвоили переменной foo пустое значение и проверили, что она действительно получила пустое значение. Далее выполнили команду if с составной командой (( foo = 5 )). Эта команда имеет два интересных аспекта: (1) она присваивает значение 5 переменной foo и (2) оценивает ее значение как истинное, потому что присваивание прошло успешно.
ПРИМЕЧАНИЕ
Важно запомнить значение оператора = в примере выше. Одиночный знак = выполняет присваивание: выражение foo = 5 говорит: «Сделать значение переменной foo равным 5». Двойной знак == определяет эквивалентность: выражение foo == 5 говорит: «Переменная foo равна 5?» Это обстоятельство может вызывать путаницу, потому что команда test интерпретирует одиночный знак = как оператор сравнения строк. Это еще одна причина предпочесть более современные составные команды [[ ]] и (( )) вместо test.
В дополнение к оператору = командная оболочка поддерживает еще несколько очень полезных операторов присваивания, перечисленных в табл. 34.3.
Таблица 34.3. Операторы присваивания
Форма записи
Описание
параметр = значение
Простое присваивание. Присваивает указанное значение указанному параметру
параметр += значение
Присваивание со сложением. Эквивалентно выражению параметр = параметр + значение
параметр -= значение
Присваивание с вычитанием. Эквивалентно выражению параметр = параметр - значение
параметр *= значение
Присваивание с умножением. Эквивалентно выражению параметр = параметр ? значение
параметр /= значение
Присваивание с целочисленным делением. Эквивалентно выражению параметр = параметр ? значение
параметр %= значение
Присваивание с делением по модулю. Эквивалентно выражению параметр = параметр % значение
параметр++
Постинкремент переменной. Эквивалентно выражению параметр = параметр + 1. (Но см. обсуждение ниже.)
параметр--
Постдекремент переменной. Эквивалентно выражению параметр = параметр - 1
++параметр
Преинкремент переменной. Эквивалентно выражению параметр = параметр + 1
--параметр
Предекремент переменной. Эквивалентно выражению параметр = параметр - 1
Эти операторы присваивания обеспечивают удобный и компактный способ записи многих арифметических вычислений. Особый интерес представляют операторы инкремента (++) и декремента (--), они увеличивают или уменьшают значение своего параметра на 1. Эти операторы заимствованы из языка программирования C и внедрены в несколько других языков программирования, включая bash.
Операторы инкремента и декремента могут находиться перед параметром или после него. Хотя в обоих случаях они увеличивают или уменьшают значение параметра на 1, тем не менее их местоположение играет важную роль. Если оператор помещается перед параметром, сначала выполняется операция инкремента (или декремента) и только потом возвращается измененное значение параметра. Если оператор помещается за параметром, операция выполняется после возврата значения. Такое поведение может показаться странным, но оно реализовано с умыслом. Взгляните на следующий пример:
[me@linuxbox ~]$ foo=1
[me@linuxbox ~]$ echo $((foo++))
1
[me@linuxbox ~]$ echo $foo
2
Если присвоить переменной foo значение 1 и затем увеличить ее значение с помощью оператора ++, следующего за именем переменной, выражение вернет прежнее значение 1 переменной foo. Однако если вывести значение переменной второй раз, мы увидим увеличенное значение. Если поместить оператор ++ перед параметром, мы получим более ожидаемый результат:
[me@linuxbox ~]$ foo=1
[me@linuxbox ~]$ echo $((++foo))
2
[me@linuxbox ~]$ 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 " "