Advanced Bash-Scripting Guide: Искусство программирования на языке сценариев командной оболочки | ||
---|---|---|
Назад | Глава 10. Циклы и ветвления | Вперед |
Инструкции case и select технически не являются циклами, поскольку не предусматривают многократное исполнение блока кода. Однако, они, как и циклы, управляют ходом исполнения программы, в зависимости от начальных или конечных условий.
Конструкция case эквивалентна конструкции switch в языке C/C++. Она позволяет выполнять тот или иной участок кода, в зависимости от результатов проверки условий. Она является, своего рода, краткой формой записи большого количества операторов if/then/else и может быть неплохим инструментом при создании разного рода меню.
case "$variable" in
"$condition1" )
command...
;;
"$condition2" )
command...
;;
esac
|
Пример 10-24. Использование case
#!/bin/bash echo; echo "Нажмите клавишу и затем клавишу Return." read Keypress case "$Keypress" in [a-z] ) echo "буква в нижнем регистре";; [A-Z] ) echo "Буква в верхнем регистре";; [0-9] ) echo "Цифра";; * ) echo "Знак пунктуации, пробел или что-то другое";; esac # Допускается указыватль диапазоны символов в [квадратных скобках]. # Упражнение: # -------- # Сейчас сценарий считывает нажатую клавишу и завершается. # Измените его так, чтобы сценарий продолжал отвечать на нажатия клавиш, # но завершался бы только после ввода символа "X". # Подсказка: заключите все в цикл "while". exit 0
Пример 10-25. Создание меню с помощью case
#!/bin/bash # Грубый пример базы данных clear # Очистка экрана echo " Список" echo " ------" echo "Выберите интересующую Вас персону:" echo echo "[E]vans, Roland" echo "[J]ones, Mildred" echo "[S]mith, Julie" echo "[Z]ane, Morris" echo read person case "$person" in # Обратите внимание: переменная взята в кавычки. "E" | "e" ) # Пользователь может ввести как заглавную, так и строчную букву. echo echo "Roland Evans" echo "4321 Floppy Dr." echo "Hardscrabble, CO 80753" echo "(303) 734-9874" echo "(303) 734-9892 fax" echo "revans@zzy.net" echo "Старый друг и партнер по бизнесу" ;; # Обратите внимание: блок кода, анализирующий конкретный выбор, завершается # двумя символами "точка-с-запятой". "J" | "j" ) echo echo "Mildred Jones" echo "249 E. 7th St., Apt. 19" echo "New York, NY 10009" echo "(212) 533-2814" echo "(212) 533-9972 fax" echo "milliej@loisaida.com" echo "Подружка" echo "День рождения: 11 февраля" ;; # Информация о Smith и Zane будет добавлена позднее. * ) # Выбор по-умолчанию. # "Пустой" ввод тоже обрабатывается здесь. echo echo "Нет данных." ;; esac echo # Упражнение: # -------- # Измените этот сценарий таким образом, чтобы он не завершал работу #+ после вывода информации о персоне, а переходил на ожидание нового #+ ввода от пользователя. exit 0
Очень хороший пример использования case для анализа аргументов, переданных из командной строки.
#! /bin/bash case "$1" in "") echo "Порядок использования: ${0##*/} <filename>"; exit 65;; # Параметры командной строки отсутствуют, # или первый параметр -- "пустой". # Обратите внимание на ${0##*/} это подстановка параметра ${var##pattern}. В результате получается $0. -*) FILENAME=./$1;; # Если имя файла (аргумент $1) начинается с "-", # то заменить его на ./$1 # тогда параметр не будет восприниматься как ключ команды. * ) FILENAME=$1;; # В противном случае -- $1. esac
Пример 10-26. Оператор case допускает использовать подстановку команд вместо анализируемой переменной
#!/bin/bash # Подстановка команд в "case". case $( arch ) in # команда "arch" возвращает строку, описывающую аппаратную апхитектуру. i386 ) echo "Машина на базе процессора 80386";; i486 ) echo "Машина на базе процессора 80486";; i586 ) echo "Машина на базе процессора Pentium";; i686 ) echo "Машина на базе процессора Pentium2 или выше";; * ) echo "Машина на другом типе процессора";; esac exit 0
Оператор case допускает использование шаблонных конструкций.
Пример 10-27. Простой пример сравнения строк
#!/bin/bash # match-string.sh: простое сравнение строк match_string () { MATCH=0 NOMATCH=90 PARAMS=2 # Функция требует два входных аргумента. BAD_PARAMS=91 [ $# -eq $PARAMS ] || return $BAD_PARAMS case "$1" in "$2") return $MATCH;; * ) return $NOMATCH;; esac } a=one b=two c=three d=two match_string $a # неверное число аргументов echo $? # 91 match_string $a $b # не равны echo $? # 90 match_string $b $d # равны echo $? # 0 exit 0
Пример 10-28. Проверка ввода
#!/bin/bash # isalpha.sh: Использование "case" для анализа строк. SUCCESS=0 FAILURE=-1 isalpha () # Проверка - является ли первый символ строки символом алфавита. { if [ -z "$1" ] # Вызов функции без входного аргумента? then return $FAILURE fi case "$1" in [a-zA-Z]*) return $SUCCESS;; # Первый символ - буква? * ) return $FAILURE;; esac } # Сравните с функцией "isalpha ()" в языке C. isalpha2 () # Проверка - состоит ли вся строка только из символов алфавита. { [ $# -eq 1 ] || return $FAILURE case $1 in *[!a-zA-Z]*|"") return $FAILURE;; *) return $SUCCESS;; esac } isdigit () # Проверка - состоит ли вся строка только из цифр. { # Другими словами - является ли строка целым числом. [ $# -eq 1 ] || return $FAILURE case $1 in *[!0-9]*|"") return $FAILURE;; *) return $SUCCESS;; esac } check_var () # Интерфейс к isalpha { if isalpha "$@" then echo "\"$*\" начинается с алфавитного символа." if isalpha2 "$@" then # Дальнейшая проверка не имеет смысла, если первй символ не буква. echo "\"$*\" содержит только алфавитные символы." else echo "\"$*\" содержит по меньшей мере один не алфавитный символ." fi else echo "\"$*\" начинсется с не алфавитного символа ." # Если функция вызвана без входного параметра, #+ то считается, что строка содержит "не алфавитной" символ. fi echo } digit_check () # Интерфейс к isdigit (). { if isdigit "$@" then echo "\"$*\" содержит только цифры [0 - 9]." else echo "\"$*\" содержит по меньшей мере один не цифровой символ." fi echo } a=23skidoo b=H3llo c=-What? d=What? e=`echo $b` # Подстановка команды. f=AbcDef g=27234 h=27a34 i=27.34 check_var $a check_var $b check_var $c check_var $d check_var $e check_var $f check_var # Вызов без параметра, что произойдет? # digit_check $g digit_check $h digit_check $i exit 0 # Сценарий дополнен S.C. # Упражнение: # -------- # Напишите функцию 'isfloat ()', которая проверяла бы вещественные числа. # Подсказка: Эта функция подобна функции 'isdigit ()', #+ надо лишь добавить анализ наличия десятичной точки.
Оператор select был заимствован из Korn Shell, и является еще одним инструментом, используемым при создании меню.
select variable [in list]
do
command...
break
done
Этот оператор предлагает пользователю выбрать один из представленных вариантов. Примечательно, что select по-умолчанию использует в качестве приглашения к вводу (prompt) -- PS3 (#? ), который легко изменить.
Пример 10-29. Создание меню с помощью select
#!/bin/bash PS3='Выберите ваш любимый овощ: ' # строка приглашения к вводу (prompt) echo select vegetable in "бобы" "морковь" "картофель" "лук" "брюква" do echo echo "Вы предпочитаете $vegetable." echo ";-))" echo break # если 'break' убрать, то получится бесконечный цикл. done exit 0
Если в операторе select список in list не задан, то в качестве списка будет использоваться список аргументов ($@), передаваемый сценарию или функции.
Сравните это с поведением оператора цикла
for variable [in list]
в котором не задан список аргументов.Пример 10-30. Создание меню с помощью select в функции
#!/bin/bash PS3='Выберите ваш любимый овощ: ' echo choice_of() { select vegetable # список выбора [in list] отсутствует, поэтому 'select' использует входные аргументы функции. do echo echo "Вы предпочитаете $vegetable." echo ";-))" echo break done } choice_of бобы рис морковь редис томат шпинат # $1 $2 $3 $4 $5 $6 # передача списка выбора в функцию choice_of() exit 0
См. так же Пример 34-3.