Управляющие конструкции: "case"
Оператор case
case (in) / esac
Оператор case является многовариантным оператором или оператором выбора. С его помощью можно искать значения, используя заданный шаблон. Если совпадение с шаблоном установлено, можно выполнять команды, основываясь исключительно на этом соответствии. Инструкции case и select технически не являются циклами, поскольку не предусматривают многократное исполнение блока кода. Однако, они, как и циклы, управляют ходом исполнения программы, в зависимости от начальных или конечных условий. Конструкции case является, своего рода, краткой формой записи большого количества операторов if/then/else и может быть неплохим инструментом при создании разного рода меню.
Ниже приводится формат оператора case:
сase ¨значение¨ in
шаблон_1)
команды_1
..........
шаблон_2)
команды_2
..........
;;
esac
или:
case "$variable" in
"$condition1" )
command...
;;
"$condition2" )
command...
;;
esac
Заключать переменные в кавычки необязательно, поскольку здесь не производится разбиения на отдельные слова.
Каждая строка с условием должна завершаться правой (закрывающей) круглой скобкой ).
Каждый блок команд, отрабатывающих по заданному условию, должен завершаться двумя символами точка с запятой ;;.
Блок case должен завершаться ключевым словом esac (case записанное в обратном порядке).
Поиск значения, совпадающего с шаблоном, выполняется по каждому шаблону. Если устанавливается соответствие с шаблоном, то оставшиеся шаблоны уже не проверяются. Эти шаблоны не принимаются во внимание даже после выполнения команд, относящихся к шаблону, с которым установлено соответствие. Если поиск соответствия по всем шаблонам оказался безрезультатным, можно принять значение с помощью символа звездочки. Этот символ используется для фиксации любых вводимых данных. Шаблонная часть может содержать метасимволы. Аналогичным образом соответствие с шаблоном устанавливается при обработке расширений имен файлов в командной строке.
* Произвольные символы
? Произвольный отдельный символ
[...] Произвольный символ из класса или диапазона
Простой оператор case
Следующий сценарий отображает приглашение для ввода чисел от 1 до 5. Число передается оператору case, переменной ANS присваивается значение ANS оператора case, и значение ANS сравнивается с каждым шаблоном. Если соответствие установлено, команды из шаблонной части выполняются до тех пор, пока не появятся символы ;; Тогда на экран выводится команда, которая информирует пользователя о сделанном выборе. Затем выполнение оператора case завершается, поскольку совпадение с шаблоном установлено. Далее выполняются операции, находящиеся после оператора case. Если соответствие не найдено, с помощью шаблона * выполняется прием всей вводимой информации. Затем отображается сообщение об ошибке.
$ pg caseselect
#!/bin/sh
#caseselect
echo -n "enter a number from 1 to 5: "
read ANS
case $ANS in
1) echo "you select 1"
;;
2) echo "you select 2"
;;
3) echo "you select 3"
;;
4) echo "you select 4"
;;
5) echo "you select 5"
;;
*) echo "`basename $0`: This is not between 1 and 5" >&2
exit 1
;;
esac
Итого:
$ caseselect
enter a number from 1 to 5: 4
you select 4
$ caseselect
enter a number from 1 to 5: qwerty
caseselect: This is not between 1 and 5
$
Применение символа pipe ( | ) при поиске по шаблону
При использовании оператора case в качестве команды (or) можно указывать символ канала (pipe |).
Например," vtl00 | vtl02") соответствут шаблону vtl00 или vtl02.
В следующем примере у пользователя запрашивают тип терминала. Если пользователь вводит vt100 или vtl02, выполняется сравнение с шаблоном “vtl00| vtl02>”. В данном случае переменной TERM присваивается значение vtl00. Если пользователь указывает тип терминала, который не соответствует шаблону, с помощью шаблона (*) выполняется прием этой информации и значение типа терминала все равно устанавливается как vt100. Наконец, за пределами действия оператора case производится экспорт переменной TERM.
Независимо от тех сведений, которые вводит пользователь (например ошибочных), переменная TERM представляет TERM=vt100 тип терминала, поскольку используется поиск по шаблону (*) и echo "setting it to vt100 anyway, so there".
$ pg caseterm
#!/bin/sh
# caseterm
echo "choices are.. vt100, vt102, vt220"
echo -n "enter your terminal type: "
read TERMINAL
case $TERMINAL in
vt100 | vt102) TERM=vt100
;;
vt220) TERM=vt220
;;
*) echo "`basename $0` : Unknown response" >&2
echo "setting it to vt100 anyway, so there"
TERM=vt100
;;
esac
export TERM
echo "Your terminal is set to $TERM"
Проверим:
$ caseterm
choices are.. vt100, vt102, vt220
enter your terminal type: vt220
Your terminal is set to vt220
$ caseterm
choices are.. vt100, vt102, vt220
enter your terminal type: qwerty
caseterm : Unknown response
setting it to vt100 anyway, so there
Your terminal is set to vt100
$
Приглашение для ввода Y или N
Оператор case , что очевидно, удобно применять при отображении запроса на продолжение обработки. Ниже приводится сценарий, в котором пользователю предлагается указать в качестве ответа либо ¨у¨, что означает продолжение обработки, либо ¨n¨ — выход из сценария. Если пользователь введет "yes", обработка будет продолжена в соответствии с частью сценария после оператора case. Если пользователь введет "no" или какой-либо другой ответ, работа со сценарием для него завершается.
$ pg caseans
#!/bin/sh
# caseans
echo -n "Do you wish to proceed [y/n]"
read ANS
case $ANS in
y|У|"yes"|Yes)
echo "yes is selected"
;;
n|N|no|No)
echo "no is selected"
exit 0 # нет ошибки, поэтому для выхода укажите 0
;;
*) echo "`basename $0` : Unknown response" >&2
exit 1
;;
esac
Проверим:
$ caseans
Do you wish to proceed [y/n]y
yes is selected
$ caseans
Do you wish to proceed [y/n]n
no is selected
$ caseans
Do you wish to proceed [y/n]jhg
caseans : Unknown response
$
Оператор case и передача системных параметров
Можно также использовать оператор case при передаче параметров в сценарии. В следующем сценарии при осуществлении проверки используется специальный параметр $#, который представляет число передаваемых аргументов. Если это число отлично от 1, сценарий завершает работу, отображая соответствующее сообщение.
Затем оператор case выполняет прием следующих параметров: start, stop или help. В дальнейшем код реализуется для каждого совпадения с этими шаблонами. При передаче неизвестного значения на экран выводится стандартное сообщение об ошибке.
$ pg caseparam
#!/bin/sh
#caseparam
if [ $# != 1 ]; then
echo " $# != 1 Usage: `basename $0` [start|stop|help]" >&2
exit 1
fi
# присвойте переменной ОРТ параметр
OPT=$1
case $OPT in
start) echo "starting..`basename $0`"
# здесь коды для начала процесса
;;
stop) echo "stopping..`basename $0`"
#здесь коды для прекращения процесса
;;
help) echo "help..`basename $0`"
# здесь коды для отображения справочной страницы
;;
*) echo "Usage: `basename $0` [start|stop|help]"
esac
Проверим:
$ caseparam start
starting..caseparam
$ caseparam stop
stopping..caseparam
$ caseparam help
help..caseparam
$ caseparam qwerty
Usage: caseparam [start|stop|help]
$ caseparam
0 != 1 Usage: caseparam [start|stop|help]
$
Прием потока ввода без применения шаблонных команд
После шаблонной части необязательно указывать команды, а возможно использовать шаблонные части для фильтрации нежелательных (ошибочных) откликов.
Предположим существование некого отдела (допустимые номера отдела: 234,453,655,454) в который необходимо отправить определенный отчет ( тип отчета может быть ¨post¨ либо ¨prior¨), сначала желательно удостовериться, что пользователь правильно ввел номер отдела, а затем уже уточнить, какой отчет выполняется. Такой подход реализуется при сравнении с шаблоном всех требуемых значений; любые другие методы неприемлемы.
В следующем сценарии указано, что если пользователь вводит номер отдела, который не совпадает со значением 234, 453, 655 или 454, то пользователь выйдет из сценария. Если номер отдела указан правильно, аналогичный подход применяется при определении типа отчета. По окончании выполнения оператора case остаются действительный номер отдела и правильный тип отчета. Ниже приводится соответствующий сценарий.
$ pg casevalid
#!/bin/sh
# casevalid
TYPE=""
echo -n "enter the account of dept No: "
read ACC
case $ACC in
234) ;;
453) ;;
655) ;;
454) ;;
*) echo "`basename $0`: Unknown dept No:" >&2
echo "try..234,453,655,454"
exit 1
esac
# если оказались здесь, то введен верный номер отдела
echo "1 - post"
echo "2 - prior"
echo -n "enter the type of report: "
read ACC_TYPE
case $ACC_TYPE in
1) TYPE=post ;;
2) TYPE=prior ;;
*) echo "`basename $0`: Unknown account type." >&2
exit 1
;;
esac
# если оказались здесь, то введен верный номер отчета
echo "now running report for dept: \"$ACC\" for the type: \"$TYPE\""
Проверим:
$ casevalid
enter the account of dept No: 234
1 - post
2 - prior
enter the type of report: 1
now running report for dept: "234" for the type: "post"
$ casevalid
enter the account of dept No: 1234567
casevalid: Unknown dept No:
try..234,453,655,454
$ casevalid
enter the account of dept No: 453
1 - post
2 - prior
enter the type of report: 6
casevalid: Unknown account type.
$
Переменные сценария, заданные по "умолчанию"
...Наличие значения переменной (подстановка).
..........................
read WHEN
echo "validating..${WHEN="Saturday"}"
..........................
Следующий пример демонстрирует функционирование оператора case аналогично нескольких операторов if/then else:
$ pg caserep
#!/bin/sh
# caserep
echo " Weekly Report"
echo -n "What day do you want to run report [Saturday] :"
# если нажать клавишу ввода, принимается заданное по умолчанию название Saturday
read WHEN
echo "validating..${WHEN="Saturday"}"
case $WHEN in
Mondaу|MONDAY|mon)
;;
Sunday|SUNDAY|sun)
;;
Saturday|SATURDAY|sat)
;;
*) echo " Are you nuts!, this report can only be run on " >&2
echo " on a Saturday, Sunday or Monday" >&2
exit 1
esac
echo "Report to run on $WHEN"
# здесь команда для выполнения действительного отчета
Проверим:
$ caserep
Weekly Report
What day do you want to run report [Saturday] :----
validating..----
Are you nuts!, this report can only be run on
on a Saturday, Sunday or Monday
$ caserep
Weekly Report
What day do you want to run report [Saturday] :mon
validating..mon
Report to run on mon
$