14.3 Использование управляющих конструкций в сценариях (Using Control Structures)¶
Помимо интерактивности, в сценарии оболочки очень полезно добавлять управляющие конструкции (control structures). До сих пор наши сценарии выполнялись последовательно от начала до конца. Это вполне работоспособно, но что если сценарию нужно принимать решения? В зависимости от ввода пользователя или вывода команды может потребоваться, чтобы сценарий выбирал тот или иной курс действий. Это реализуется с помощью управляющих конструкций. В данном разделе рассматриваются следующие элементы такого рода:
- Использование конструкций if/then/else
- Использование конструкций case
- Использование конструкций цикла
Начнём с обзора конструкции if/then.
Использование конструкций if/then (Using if/then Structures)¶
Использование конструкции if/then/else в сценарии оболочки позволяет выполнять различные команды в зависимости от того, истинно или ложно заданное условие. Структура выглядит следующим образом:
Часть if структуры указывает оболочке вычислить, является ли заданное условие истинным или ложным. Если оно истинно, выполняются команды под частью then. Если условие оказывается ложным, выполняются команды под частью else.
Например, в сценарии, с которым мы работали в данной части главы, мы просили пользователя ввести имя каталога, который он хочет добавить в переменную окружения PATH. При добавлении каталога в PATH оболочка не проверяет, существует ли указанный каталог на самом деле. Было бы полезно выполнить быструю проверку и убедиться, что указанный каталог существует. Если да — добавить его в переменную PATH. Если нет — вывести на экран сообщение об ошибке. Именно это делает сценарий из следующего примера:
#!/bin/bash
#A script for adding a directory to the PATH environment variable
echo "What directory do you want to add to the PATH?"
read MYNEWPATH
if [ -d "$MYNEWPATH" ]; then
echo "The " $MYNEWPATH " directory exists."
echo "Adding the " $MYNEWPATH " directory to PATH."
PATH=$PATH:$MYNEWPATH
export PATH
echo "Your PATH environment variable is now:"
echo $PATH
else
echo $MYNEWPATH " doesn't exist."
fi
exit 0
В этом примере условие [ -d "$MYNEWPATH" ] вызывает утилиту test и указывает ей проверить, существует ли каталог, содержащийся в переменной MYNEWPATH (как задаётся параметром -d).
Если test возвращает значение TRUE, выполняются шаги непосредственно под оператором if. Если же программа test возвращает FALSE, выполняются операторы под частью else. В данном случае будет выведено сообщение об ошибке с указанием, что каталог не существует. При запуске этого сценария с указанием допустимого каталога отображается следующий вывод:
rtracy@openSUSE:~> ./addpath
What directory do you want to add to the PATH?
/tmp
The /tmp directory exists.
Adding the /tmp directory to PATH.
You PATH environment variable is now:
/usr/lib/mpi/gcc/openmpi/bin:/home/rtracy/bin:/usr/local/bin:/usr/bin:
/bin:/usr/bin/X11:/usr/X11R6/bin:/usr/games:/tmp
Помимо параметра -d в конструкции if/then/else для проверки условий, можно использовать также саму команду test. Команда test поддерживает следующие параметры:
-d— Проверяет, существует ли указанный файл и является ли он каталогом.-e— Проверяет, существует ли указанный файл. При этом не различаются файлы и каталоги.-f— Проверяет, существует ли указанный файл и является ли он обычным файлом.-G— Проверяет, существует ли указанный файл и принадлежит ли он указанной группе.-hили-L— Проверяет, существует ли указанный файл и является ли он символьной ссылкой.-O— Проверяет, существует ли указанный файл и принадлежит ли он указанному идентификатору пользователя.-r— Проверяет, существует ли указанный файл и предоставлено ли право на чтение.-w— Проверяет, существует ли указанный файл и предоставлено ли право на запись.-x— Проверяет, существует ли указанный файл и предоставлено ли право на выполнение.
Например, следующая конструкция проверяет, существует ли файл myfile в каталоге /home/rtracy:
С помощью команды test можно проверять не только существование файлов. Ниже приведены примеры некоторых условий, доступных для проверки командой test.
Истинно, если строки совпадают:
Истинно, если строки не равны:
Истинно, если оба числа одинаковы:
Истинно, если num1 меньше num2:
Истинно, если num1 больше num2:
В сценариях можно использовать также родственную конструкцию case. Рассмотрим её применение.
Использование конструкций case (Using case Structures)¶
Оператор case — это, по сути, расширенный вариант оператора if/then. Оператор if/then отлично справляется, когда условие может быть вычислено одним из двух способов. В предыдущих примерах условие могло принимать значение «истина» или «ложь». Но что если условие может принимать множество различных значений, а вы всё равно хотите, чтобы сценарий выполнял определённые действия в зависимости от результата? В этом случае используйте оператор case.
Совет
Вместо оператора case можно использовать целую серию операторов if/then. Однако это быстро превращается в нечитаемый код и считается дурным тоном. Если условие может принимать более двух значений, следует использовать оператор case.
Синтаксис конструкции case выглядит следующим образом:
По сути, оператор case сравнивает значение указанной переменной со списком вариантов ответов внутри конструкции case. При совпадении выполняются команды, связанные с этим вариантом. Команды для всех остальных вариантов игнорируются.
Например, можно написать сценарий, который спрашивает пользователей, в каком месяце они родились. В зависимости от ответа сценарий может выдавать персонализированный ответ с помощью оператора case. Ниже приведён пример такого сценария:
#!/bin/bash
#A simple script to demonstrate the case structure.
echo "What month were you born in?"
read MYMONTH
case $MYMONTH in
December | January | February ) echo "Being born in" $MYMONTH",
you were born during the winter in the Northern Hemisphere."
;;
March | April | May ) echo "Being born in" $MYMONTH",
you were born during the spring in the Northern Hemisphere."
;;
June | July | August ) echo "Being born in" $MYMONTH",
you were born during the summer in the Northern Hemisphere."
;;
September | October | November ) echo "Being born in" $MYMONTH",
you were born during the fall in the Northern Hemisphere."
;;
* ) echo "Sorry, I'm not familiar with that month!"
;;
esac
exit 0
Этот сценарий спрашивает пользователей, в каком месяце они родились, а затем определяет время года с помощью конструкции case. Предусмотрено пять вариантов:
- December, January или February
- March, April или May
- June, July или August
- September, October или November
*
Обратите внимание, что различные значения на одной строке разделяются символом конвейера (|), который означает «или». Если ответ пользователя совпадает с одним из значений, выполняется связанная с этой строкой команда. В следующем примере сценарий был запущен, и пользователь указал в качестве месяца рождения июнь (June):
rtracy@openSUSE:~> ./casetest
What month were you born in?
June
Being born in June, you were born during the summer in the Northern Hemisphere.
Поскольку значение переменной MYMONTH совпало со строкой в операторе case для июня, была выполнена команда echo для варианта June, July или August. Обратите внимание, что в конце оператора case добавлен ещё один вариант с использованием звёздочки (*). Этот вариант позволяет сообщить пользователям о том, что произошло, если их ответ не совпал ни с одним из перечисленных в операторе case вариантов.
Использование конструкций цикла (Using Looping Structures)¶
Конструкции if/then/else и case называются ветвящимися конструкциями (branching structures). В зависимости от результата вычисления условия сценарий разветвляется в том или ином направлении. В сценарии оболочки можно использовать также конструкции цикла (looping structures). Конструкции цикла бывают трёх видов: цикл while, цикл until и цикл for. Цикл while выполняется снова и снова до тех пор, пока указанное условие остаётся истинным. Структура цикла while выглядит следующим образом:
Цикл while будет повторяться до тех пор, пока условие не станет ложным.
В дополнение к циклу while в сценарии можно использовать цикл until. Он работает обратным образом: цикл until выполняется снова и снова до тех пор, пока условие является ложным. Как только условие становится истинным, цикл завершается. Структура цикла until выглядит следующим образом:
Можно также использовать цикл for, который работает иначе, чем циклы until и while. Циклы until и while повторяются неограниченное количество раз до выполнения заданного условия. Цикл for, напротив, повторяется заданное количество раз.
Для определения количества итераций цикла for широко применяется команда seq, генерирующая последовательность чисел. Команда seq поддерживает три варианта создания числовой последовательности:
- Если указано одно значение, последовательность начинается с 1, увеличивается на 1 и заканчивается на указанном значении.
- Если указаны два значения, последовательность начинается с первого значения, увеличивается на 1 и заканчивается на втором значении.
- Если указаны три значения, последовательность начинается с первого значения, увеличивается на второе значение и заканчивается на третьем значении.
Рассмотрим следующий пример:
Эта команда создаёт последовательность чисел, начинающуюся с 5, увеличивающуюся на 1 и заканчивающуюся на 15. Ниже показан пример использования seq в цикле for:
Наибольшая опасность при использовании конструкций цикла — это возможность попасть в бесконечный цикл (infinite loop). Это происходит, когда условие никогда не изменяется до значения, прерывающего цикл. В такой ситуации сценарий «зависает», поскольку он продолжает выполнять одну и ту же циклическую конструкцию снова и снова, и будет делать это до тех пор, пока вы вручную не прервёте его с помощью сочетания клавиш Ctrl+C.
Давайте попрактикуемся в работе с базовыми сценариями оболочки в следующем упражнении.
Упражнение 14-1. Создание базового сценария оболочки
В этом упражнении вы будете практиковаться в создании базового сценария оболочки. Сценарий будет запрашивать у пользователя три числа, а затем спрашивать, нужно ли их сложить или вычислить среднее значение. Кроме того, вы добавите право на выполнение файла, чтобы владелец мог его запускать.
Это упражнение можно выполнить на виртуальной машине, прилагаемой к книге. Запустите снимок 14-1 для получения правильно настроенной среды.
Видео
Посмотрите видеозапись упражнения 14-1 с демонстрацией выполнения данного задания.
Выполните следующие шаги:
- При необходимости загрузите систему Linux и войдите в систему как обычный пользователь.
- Перейдите в каталог
~/bin. - В приглашении командной строки введите
vi domath. -
Введите следующий сценарий:
#!/bin/bash #A script to do some simple math. clear declare -i A declare -i B declare -i C declare -i ANSWER echo "Enter the first number:" read A echo "Enter the second number:" read B echo "Enter the third number:" read C echo "What would you like to do with these numbers?" echo "P: Add them up!" echo "V: Average them!" echo "Enter your choice:" read CHOICE case $CHOICE in p | P ) ANSWER=A+B+C ;; v | V ) ANSWER=A+B+C ANSWER=$ANSWER/3 ;; esac echo "Your answer is" $ANSWER "." exit 0 -
Сохраните изменения в сценарии и выйдите из
vi. - Сделайте сценарий исполняемым для владельца файла, введя в приглашении командной строки
chmod u+x domath. - Проверьте сценарий, введя
domathв приглашении командной строки. - Протестируйте сценарий и убедитесь, что он работает правильно.