fi
Если вы введете 5, сценарий отобразит на экране слово «Отлично», при вводе 4 вы увидите слово «Хорошо» и так далее. Если вы введете 0, 1 или число больше пяти, вы увидите на экране последнюю фразу: «Как вообще можно было получить такую оценку???».
Конструкция case-esac
Конструкция выбора (case — выбор) имеет следующий синтаксис:
case значение in
шаблон1) список1 ;;
…
шаблонN) списокN ;;
esac
Рассмотрим сценарий (см. листинг 19.3), аналогичный сценарию 19.2, но использующий конструкцию case вместо if.
Листинг 19.3. Пример использования оператора case
echo –n " Какую оценку ты получил сегодня по программированию? "
read x
case $x in
5) echo "Отлично !" ;;
4) echo "Хорошо" ;;
3) echo "Удовлетворительно" ;;
2) echo "Надо бы пересдать" ;;
*) echo "Как вообще можно было получить такую оценку???" ;;
esac
Работа сценария аналогична первому сценарию: при вводе оценок 2, 3, 4, 5 будут отображены соответствующие сообщения, а во всех остальных случаях — последнее сообщение.
Примечание. Структура оператора case больше напоминает структуру оператора case в языке Pascal, чем в языке С. Последняя строка выбора с шаблоном *) будет выбрана, когда не произойдет ни одного совпадения с ранее указанными шаблонами. Если же произошло совпадение с шаблоном шаблонN, то будет выполнен список списокN. После выполнения списка команд списокN будет произведен выход из структуры case —так же как и в Pascal. В языке С наблюдается нечто другое: если будет обнаружено совпадение, скажем с шаблоном3, то будут выполнены последовательности операторов 3, 4, 5, … N. Чтобы прервать выполнение блока case в языке С нужно использовать оператор break. В bash же такого нет.
Если для одного списка команд нужно описать два или более шаблонов, используется символ | (OR).
case num in
1|2|3) echo "1 or 2 or 3" ;;
4|5) echo "4 or 5" ;;
*) echo "other num" ;;
esac
Циклы
Интерпретаторы bash и ksh поддерживают циклы for, while, until, select, a интерпретатор sh только for и while.
Синтаксис цикла for:
for имя_переменной in список1 do
список2
done
Простой пример:
for i in 1 2 3 4 5; do echo $i; done
На экране вы увидите:
1 2 3 4 5
Еще раз напомню, что любой список в bash должен заканчиваться точкой с запятой. Начинающие «программисты» делают много ошибок, связанных именно с этой особенностью списков. Пример использования: построчно вывести содержимое файла /etc/passwd вы можете с помощью такого цикла:
for str in `cat /etc/passwd` do
echo "$str";
done
Цикл for закончит свою работу, когда будет обработан последний элемент списка, в данном случае, когда на экран будет выведена последняя строка файла /etc/passwd.
Синтаксис цикла while:
while список1 do
список2
done
Цикл while будет выполняться, пока условие, заданное в списке список!,
будет истинным. Поэтому цикл while иногда называют циклом с истинным условием. Например,
х=1
while [$х –It 10]
do
echo $х
X = $(( $Х + 1 ))
done
На экране вы увидите:
1 2 3 4 5 6 7 8 9
Когда переменная х примет значение 10, цикл завершит свою работу, так как программа test вернет значение false (x уже не меньше, а равен 10). Цикл until (до) имеет похожую структуру, но выполняется несколько иначе:
until список1 do
список2
done
Цикл until прекратит работу, когда условие, указанное в списке список1, станет истинным. Другими словами, он будет выполняться пока это условие ложно. Цикл while, наоборот, выполняется пока условие истинно. Лучше всего разница между этими циклами видна на примере (сравните листинги 19.4 и 19.5)
Листинг 19.4. Цикл while
х=1;
while ! [$х –ge 10]
do echo $x echo $x
X = $ (($Х + 1))
done
Листинг 19.5. Цикл until
х=1;
until [$x –ge 10]
do
X=$(($Х + 1))
done
Циклы, приведенные в листингах 19.4 и 19.5, выведут одинаковую последовательность цифр на экран:
1 2 3 4 5 6 7 8 9 10
Рассмотрим еще один полезный цикл select, который позволяет создавать нумерованные пункты меню. Его конструкция такова:
select имя in список1
do
список2
done
Пример:
echo "Выберите файл для просмотра
select file in /home/den/temp/* QUIT
do
if [-e $file]; then less $file
else
break
done;
В моем временном каталоге /home/den/temp находится всего два файла — file.txt, proto.txt, поэтому на экране монитора будет отображено следующее:
Выберите файл для просмотра:
/home/den/temp/.
/home/den/temp/..
/home/den/temp/file.txt
/home/den/temp/proto.txt
QUIT
Первые два файла — это ссылки на текущий и родительский каталоги. Пункты меню 3 и 4 — это файлы, которые можно выбрать для просмотра. QUIT — это последний элемент списка. При его выборе сработает оператор break и цикл завершится.
19.7.7. Подстановка переменных
Мы уже рассмотрели подстановку команд, сейчас рассмотрим подстановку переменных (см. табл. 19.41).
Подстановка переменных Таблица 19.41
Конструкция Описание ${переменная:-значение} Если переменная определена и не является пустой строкой, подставляется ее значение, иначе подставляется значение, указанное в конструкции. Реальное значение переменной при этом не изменяется ${переменна:=значение} Значение присваивается переменной, если она не определена или является пустой строкой ${переменная:?сообщение} Если переменная не определена или является пустой строкой, выводится указанное сообщение ${переменная:+значение} Если переменная инициализирована (определена), вместо нее используется указанное в конструкции значение. Реальное значение переменной не изменяется ${переменная} Если переменная определена, то подставляется ее значение. Скобки используются лишь тогда, если после переменной стоит символ, который может «приклеиться» к имени переменной
Пример.
${1 :? "Не хватает параметра"}
Данное сообщение будет выведено, если сценарий будет запущен без параметров. Если указать хотя бы один параметр, сообщение не будет отображаться на экране.
Описание функции выглядит так:
имя() { список; }
Пример:
cdir()
{
# изменяем каталог
cd /
}
При выполнении функция не создает нового процесса, а выполняется в среде процесса, содержащего эту функцию. Аргументы функции можно передать ей как обыкновенные параметры при вызове сценария. Функции можно описывать в любом месте сценария, но вызов функции должен осуществляться только после ее описания. Возвращаясь к примеру, модифицируйте функцию:
#!/bin/bash
# файл fn
echo $$
cdir()
{
# изменяем каталог
echo "Х=$Х"
Х=2
echo "Params $0 $# $1 $2"
echo "PID = $$"
return 0
cd $1
}
X=1
echo "X=$X"
cdir /etc
# вызов функции "cd" с параметрами
echo $?
echo "X=$X"
На экране вы увидите примерно следующую информацию:
788
Х=1
Х=1
Params fn l /etc
788
0
Х=2
Проанализируем полученную информацию. Как уже отмечалось, функция не порождает нового процесса, поэтому PID остался равным 788 как до вызова функции, так и во время ее выполнения. Переменная X доступна нашей функции, потому что описана до вызова функции. Функция «видит» значение переменной X, установленное в основном блоке сценария. Затем функция изменяет значение переменной X и передает его в основной блок (Х=2). Функции был передан только один параметр — /etc, вместо второго параметра была отображена пустая строка. Имя файла осталось прежним — fn. Обратите внимание на важный момент: функция сообщила нам много полезной информации об устройстве функций в bash, но не оправдала своего названия — cdir (change dir). Реально изменения каталога не произошло, потому что перед выполнением команды cd была выполнена команда return с кодом завершения 0, которая прервала выполнение функции.